1. 队列

1.1 设计循环双端队列(641)

  • 双向链表

    1. class MyCircularDeque {
    2. private int capacity;
    3. private int size;
    4. private Node head;
    5. private Node tail;
    6. public MyCircularDeque(int k) {
    7. capacity = k;
    8. size = 0;
    9. head = new Node(-1, null, null);
    10. tail = new Node(-2, head, null);
    11. head.next = tail;
    12. }
    13. public boolean insertFront(int value) {
    14. if ( size >= capacity ) {
    15. return false;
    16. }
    17. size++;
    18. Node temp = head.next;
    19. head.next = new Node(value, head, temp);
    20. temp.prev = head.next;
    21. return true;
    22. }
    23. public boolean insertLast(int value) {
    24. if ( size >= capacity ) {
    25. return false;
    26. }
    27. size++;
    28. Node last = tail.prev;
    29. last.next = new Node(value, last, tail);
    30. tail.prev = last.next;
    31. return true;
    32. }
    33. public boolean deleteFront() {
    34. if (size == 0) {
    35. return false;
    36. }
    37. size--;
    38. Node temp = head.next.next;
    39. head.next = head.next.next;
    40. temp.prev = head;
    41. return true;
    42. }
    43. public boolean deleteLast() {
    44. if (size == 0) {
    45. return false;
    46. }
    47. size--;
    48. Node temp = tail.prev.prev;
    49. temp.next = temp.next.next;
    50. tail.prev = temp;
    51. return true;
    52. }
    53. public int getFront() {
    54. if (size == 0) {
    55. return -1;
    56. }
    57. Node temp = head.next;
    58. return temp.value;
    59. }
    60. public int getRear() {
    61. if (size == 0) {
    62. return -1;
    63. }
    64. Node temp = tail.prev;
    65. return temp.value;
    66. }
    67. public boolean isEmpty() {
    68. return size == 0;
    69. }
    70. public boolean isFull() {
    71. return size == capacity;
    72. }
    73. private static class Node {
    74. int value;
    75. Node prev;
    76. Node next;
    77. public Node(int value, Node prev, Node next) {
    78. this.value = value;
    79. this.prev = prev;
    80. this.next = next;
    81. }
    82. }
    83. }
  • 数组: ```java

public class MyCircularDeque {

  1. // 1、不用设计成动态数组,使用静态数组即可
  2. // 2、设计 head 和 tail 指针变量
  3. // 3、head == tail 成立的时候表示队列为空
  4. // 4、tail + 1 == head 表示为满
  5. // 5、注意做减法指针可能变成负数 可以用 (tail - 1 + capacity ) % capacity 来做tail移位
  6. private final int capacity;
  7. private final int[] arr;
  8. private int head;
  9. private int tail;
  10. public MyCircularDeque(int k) {
  11. // 多存一个用于区分队列满和空的情况
  12. capacity = k + 1;
  13. arr = new int[capacity];
  14. head = 0;
  15. tail = 0;
  16. }
  17. public boolean insertFront(int value) {
  18. if (isFull()) {
  19. return false;
  20. }
  21. head = (head - 1 + capacity) % capacity;
  22. arr[head] = value;
  23. return true;
  24. }
  25. public boolean insertLast(int value) {
  26. if (isFull()) {
  27. return false;
  28. }
  29. arr[tail] = value;
  30. tail = (tail + 1) % capacity;
  31. return true;
  32. }
  33. public boolean deleteFront() {
  34. if (isEmpty()) {
  35. return false;
  36. }
  37. // front 被设计在数组的开头,所以是 +1
  38. head = (head + 1) % capacity;
  39. return true;
  40. }
  41. public boolean deleteLast() {
  42. if (isEmpty()) {
  43. return false;
  44. }
  45. // rear 被设计在数组的末尾,所以是 -1
  46. tail = (tail - 1 + capacity) % capacity;
  47. return true;
  48. }
  49. public int getFront() {
  50. if (isEmpty()) {
  51. return -1;
  52. }
  53. return arr[head];
  54. }
  55. public int getRear() {
  56. if (isEmpty()) {
  57. return -1;
  58. }
  59. // 当 tail 为 0 时防止数组越界才加的capacity
  60. return arr[(tail - 1 + capacity) % capacity];
  61. }
  62. public boolean isEmpty() {
  63. return head == tail;
  64. }
  65. public boolean isFull() {
  66. // 注意:这个设计是非常经典的做法
  67. return (tail + 1) % capacity == head;
  68. }

}

  1. <a name="qF8oM"></a>
  2. ### 1.2 滑动窗口最大值(239)
  3. - 直接循环O(n^2)
  4. ```java
  5. public int[] maxSlidingWindow(int[] nums, int k) {
  6. int[] resultArr = new int[nums.length - k + 1];
  7. for (int i = 0; i < nums.length - k + 1; i++) {
  8. int max = nums[i];
  9. for (int j = i; j < i + k; j++) {
  10. max = Math.max(max, nums[j]);
  11. }
  12. resultArr[i] = max;
  13. }
  14. return resultArr;
  15. }
  • 借助队列

    1.3 层次遍历二叉树(102)

  • BFS即可

    2. 栈

    2.1 最小栈(155)

    1. class MinStack {
    2. Deque<Integer> stack;
    3. Deque<Integer> minStack;
    4. public MinStack() {
    5. stack = new LinkedList<Integer>();
    6. minStack = new LinkedList<Integer>();
    7. minStack.push(Integer.MAX_VALUE);
    8. }
    9. public void push(int x) {
    10. stack.push(x);
    11. minStack.push(Math.min(minStack.peek(), x));
    12. }
    13. public void pop() {
    14. stack.pop();
    15. minStack.pop();
    16. }
    17. public int top() {
    18. return stack.peek();
    19. }
    20. public int getMin() {
    21. return minStack.peek();
    22. }
    23. }

    2.2 删除链表第N个元素

  • 解法一:栈,pop出 n+1个元素

    1. public ListNode removeNthFromEnd(ListNode head, int n) {
    2. ListNode dummyHead = new ListNode(0, head);
    3. ListNode temp = dummyHead;
    4. Stack<ListNode> stack = new Stack<>();
    5. while (null != temp) {
    6. stack.push(temp);
    7. temp = temp.next;
    8. }
    9. ListNode prev = stack.pop();
    10. for (int i = 0; i < n; i++) {
    11. prev = stack.pop();
    12. }
    13. if (prev.next != null) {
    14. prev.next = prev.next.next;
    15. }
    16. return dummyHead.next;
    17. }
  • 解法二:双指指针,slow和fast间隔N个位置

    2.3 有效括号(20)

  • 解法一:用栈

    1. public boolean isValid(String s) {
    2. if (s.length() % 2 == 1) {
    3. return false;
    4. }
    5. Map<Character, Character> map = new HashMap<>();
    6. map.put('(', ')');
    7. map.put('[', ']');
    8. map.put('{', '}');
    9. Stack<Character> stack = new Stack<>();
    10. char[] charArr = s.toCharArray();
    11. for (char c : charArr) {
    12. if (map.containsKey(c)) {
    13. stack.push(c);
    14. continue;
    15. }
    16. if (stack.isEmpty()) {
    17. return false;
    18. }
    19. Character temp = stack.pop();
    20. if (!map.get(temp).equals(c)) {
    21. return false;
    22. }
    23. }
    24. return stack.isEmpty();
    25. }

    2.4 接雨水(42)hard

  • 解法一:栈 ```java public int trap(int[] height) {

    1. Deque<Integer> stack = new LinkedList<Integer>();
    2. int result = 0;
    3. for (int i = 0; i < height.length; ++i) {
    4. while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
    5. int top = stack.pop();
    6. if (stack.isEmpty()) {
    7. break;
    8. }
    9. int left = stack.peek();
    10. int widthTemp = i - left - 1;
    11. int heightTemp = Math.min(height[left], height[i]) - height[top];
    12. result += widthTemp * heightTemp;
    13. }
    14. stack.push(i);
    15. }
    16. return result;

    }

```

  • 解法二:动态规划:见动态规划章节

    2.5 柱状图中最大的矩形(84)hard

  • 单调栈解决

单调栈关注一下
序号 题目 题解
42. 接雨水(困难) 暴力解法、优化、双指针、单调栈
739. 每日温度(中等) 暴力解法 + 单调栈
496. 下一个更大元素 I(简单) 暴力解法、单调栈
316. 去除重复字母(困难) 栈 + 哨兵技巧(Java、C++、Python)
901. 股票价格跨度(中等) 「力扣」第 901 题:股票价格跨度(单调栈)
402. 移掉K位数字
581. 最短无序连续子数组