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;}