1.队列
1.1 【中等】设计循环双端队列(641)
/**
* 可使用Deque,或者直接阅读源码
*/
class MyCircularDeque {
private Deque<Integer> deque;
private Integer count;
public MyCircularDeque(int k) {
deque = new ArrayDeque<>();
this.count = k;
}
public boolean insertFront(int value) {
if (isFull()) {
return false;
}
deque.addFirst(value);
return true;
}
public boolean insertLast(int value) {
if (isFull()) {
return false;
}
deque.addLast(value);
return true;
}
public boolean deleteFront() {
if (isEmpty()) {
return false;
}
deque.removeFirst();
return true;
}
public boolean deleteLast() {
if (isEmpty()) {
return false;
}
deque.removeLast();
return true;
}
public int getFront() {
if (isEmpty()) {
return -1;
}
return deque.getFirst();
}
public int getRear() {
if (isEmpty()) {
return -1;
}
return deque.getLast();
}
public boolean isEmpty() {
return deque == null || deque.size() == 0;
}
public boolean isFull() {
return deque.size() == count;
}
}
1.2 【困难】滑动窗口最大值(239)
/**
* 使用优先级队列最大堆,数组0:值,数组1:下标
*/
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
PriorityQueue<int[]> pq = new PriorityQueue<>(
(pair1, pair2) -> pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[
for (int i = 0; i < k; ++i) {
pq.offer(new int[]{nums[i], i});
}
int[] ans = new int[n - k + 1];
ans[0] = pq.peek()[0];
for (int i = k; i < n; ++i) {
pq.offer(new int[]{nums[i], i});
while (pq.peek()[1] <= i - k) {
pq.poll();
}
ans[i - k + 1] = pq.peek()[0];
}
return ans;
}
1.3 【中等】层次遍历二叉树(102)
/**
* 使用队列
*/
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret = new ArrayList<>();
if (root == null) {
return ret;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
List<Integer> level = new ArrayList<>();
int currentLevelSize = queue.size();
for (int i = 1; i <= currentLevelSize; ++i) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
ret.add(level);
}
return ret;
}
2.栈
2.1 【简单】最小栈(155)
/**
* 使用两个栈进行配合
*/
class MinStack {
Deque<Integer> xStack;
Deque<Integer> minStack;
public MinStack() {
xStack = new LinkedList<>();
minStack = new LinkedList<>();
minStack.push(Integer.MAX_VALUE);
}
public void push(int x) {
xStack.push(x);
minStack.push(Math.min(minStack.peek(), x));
}
public void pop() {
xStack.pop();
minStack.pop();
}
public int top() {
return xStack.peek();
}
public int getMin() {
return minStack.peek();
}
}
2.2 【简单】有效括号(20)
/**
* 使用一个栈就可以了,左半边压栈,右半边出栈,如果为空或者不为对应符号,就返回错误
*/
public boolean isValid(String s) {
int n = s.length();
if (n % 2 == 1) {
return false;
}
Map<Character, Character> pairs = new HashMap<Character, Character>() {{
put(')', '(');
put(']', '[');
put('}', '{');
}};
Deque<Character> stack = new LinkedList<>();
for (int i = 0; i < n; i++) {
char ch = s.charAt(i);
if (pairs.containsKey(ch)) {
if (stack.isEmpty() || !stack.peek().equals(pairs.get(ch))) {
return false;
}
stack.pop();
} else {
stack.push(ch);
}
}
return stack.isEmpty();
}
2.3 【困难】接雨水(42)
/**
* 循环使用单调栈
*/
public int trap(int[] height) {
Deque<Integer> stack = new LinkedList<>();
int result = 0;
for (int i = 0; i < height.length; ++i) {
while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
int top = stack.pop();
if (stack.isEmpty()) {
break;
}
int left = stack.peek();
int widthTemp = i - left - 1;
int heightTemp = Math.min(height[left], height[i]) - height[top];
result += widthTemp * heightTemp;
}
stack.push(i);
}
return result;
}
2.4 【困难】柱状图中最大的矩形(84)
/**
* 正反单调栈
*/
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] left = new int[n];
int[] right = new int[n];
Deque<Integer> monoStack = new ArrayDeque<>();
for (int i = 0; i < n; ++i) {
while (!monoStack.isEmpty() && heights[monoStack.peek()] >= heights[i]) {
monoStack.pop();
}
left[i] = (monoStack.isEmpty() ? -1 : monoStack.peek());
monoStack.push(i);
}
monoStack.clear();
for (int i = n - 1; i >= 0; --i) {
while (!monoStack.isEmpty() && heights[monoStack.peek()] >= heights[i]) {
monoStack.pop();
}
right[i] = (monoStack.isEmpty() ? n : monoStack.peek());
monoStack.push(i);
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
}
return ans;
}
2.5 【中等】每日温度(739)
/**
* 使用单调栈即可,后往前遍历
*/
public int[] dailyTemperatures(int[] temperatures) {
int n = temperatures.length;
int[] res = new int[n];
int[] index = new int[n];
Deque<Integer> dq = new LinkedList<>();
for (int i = n-1; i >=0; i--) {
while (!dq.isEmpty() && temperatures[i] >= temperatures[dq.peek()]) {
dq.pop();
}
index[i] = dq.isEmpty() ? i : dq.peek();
dq.push(i);
}
for (int i = 0; i < n; i++) {
res[i] = index[i] - i;
}
return res;
}
2.6 【简单】下一个更大元素 I(496)
/**
* 第 1 个子问题:如何更高效地计算nums2中每个元素右边的第一个更大的值;
* 第 2 个子问题:如何存储第 1 个子问题的结果。
* 使用单调栈即可,后往前遍历
*/
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Map<Integer, Integer> map = new HashMap<>();
Deque<Integer> stack = new ArrayDeque<>();
for (int i = nums2.length - 1; i >= 0; --i) {
int num = nums2[i];
while (!stack.isEmpty() && num >= stack.peek()) {
stack.pop();
}
map.put(num, stack.isEmpty() ? -1 : stack.peek());
stack.push(num);
}
int[] res = new int[nums1.length];
for (int i = 0; i < nums1.length; ++i) {
res[i] = map.get(nums1[i]);
}
return res;
}
2.7 【中等】 去除重复字母(316)
/**
* 有点难,死记就好了,需要用到单调栈
*/
public static String removeDuplicateLetters(String s) {
boolean[] vis = new boolean[26];
int[] num = new int[26];
// 统计每个字符个数
for (int i = 0; i < s.length(); i++) {
num[s.charAt(i) - 'a']++;
}
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (!vis[ch - 'a']) {
// 单调栈
while (sb.length() > 0 && sb.charAt(sb.length() - 1) > ch) {
if (num[sb.charAt(sb.length() - 1) - 'a'] > 0) {
vis[sb.charAt(sb.length() - 1) - 'a'] = false;
sb.deleteCharAt(sb.length() - 1);
} else {
break;
}
}
vis[ch - 'a'] = true;
sb.append(ch);
}
// 个数减一
num[ch - 'a'] -= 1;
}
return sb.toString();
}
2.8 【中等】 股票价格跨度(901)
/**
* 单调栈
*/
public class StockSpanner {
Stack<Integer> prices, weights;
public StockSpanner() {
prices = new Stack();
weights = new Stack();
}
public int next(int price) {
int w = 1;
// 向前出栈,找到比这天更大的数据
while (!prices.isEmpty() && prices.peek() <= price) {
prices.pop();
w += weights.pop();
}
prices.push(price);
weights.push(w);
return w;
}
}
2.9 【中等】 移掉K位数字(402)
/**
* 单调栈
*/
public String removeKdigits(String num, int k) {
Deque<Character> deque = new LinkedList<>();
int length = num.length();
for (int i = 0; i < length; ++i) {
char digit = num.charAt(i);
// 单调栈 如果前一个元素比后一个元素大,直接删就可以了,肯定会比不删小
while (!deque.isEmpty() && k > 0 && deque.peekLast() > digit) {
deque.pollLast();
k--;
}
deque.offerLast(digit);
}
// 如果没有删完,继续删
for (int i = 0; i < k; ++i) {
deque.pollLast();
}
StringBuilder ret = new StringBuilder();
boolean leadingZero = true;
// 删除前面的0
while (!deque.isEmpty()) {
char digit = deque.pollFirst();
if (leadingZero && digit == '0') {
continue;
}
leadingZero = false;
ret.append(digit);
}
return ret.length() == 0 ? "0" : ret.toString();
}
2.10 【中等】 最短无序连续子数组(581)
/**
* 做一个排序,找到和原数组元素不一样的起点和终点
*/
public int findUnsortedSubarray(int[] nums) {
if (isSorted(nums)) {
return 0;
}
int[] numsSorted = new int[nums.length];
System.arraycopy(nums, 0, numsSorted, 0, nums.length);
Arrays.sort(numsSorted);
int left = 0;
while (nums[left] == numsSorted[left]) {
left++;
}
int right = nums.length - 1;
while (nums[right] == numsSorted[right]) {
right--;
}
return right - left + 1;
}
public boolean isSorted(int[] nums) {
for (int i = 1; i < nums.length; i++) {
if (nums[i] < nums[i - 1]) {
return false;
}
}
return true;
}