1. 队列
1.1 设计循环双端队列(641)
双向链表
class MyCircularDeque {
private int capacity;
private int size;
private Node head;
private Node tail;
public MyCircularDeque(int k) {
capacity = k;
size = 0;
head = new Node(-1, null, null);
tail = new Node(-2, head, null);
head.next = tail;
}
public boolean insertFront(int value) {
if ( size >= capacity ) {
return false;
}
size++;
Node temp = head.next;
head.next = new Node(value, head, temp);
temp.prev = head.next;
return true;
}
public boolean insertLast(int value) {
if ( size >= capacity ) {
return false;
}
size++;
Node last = tail.prev;
last.next = new Node(value, last, tail);
tail.prev = last.next;
return true;
}
public boolean deleteFront() {
if (size == 0) {
return false;
}
size--;
Node temp = head.next.next;
head.next = head.next.next;
temp.prev = head;
return true;
}
public boolean deleteLast() {
if (size == 0) {
return false;
}
size--;
Node temp = tail.prev.prev;
temp.next = temp.next.next;
tail.prev = temp;
return true;
}
public int getFront() {
if (size == 0) {
return -1;
}
Node temp = head.next;
return temp.value;
}
public int getRear() {
if (size == 0) {
return -1;
}
Node temp = tail.prev;
return temp.value;
}
public boolean isEmpty() {
return size == 0;
}
public boolean isFull() {
return size == capacity;
}
private static class Node {
int value;
Node prev;
Node next;
public Node(int value, Node prev, Node next) {
this.value = value;
this.prev = prev;
this.next = next;
}
}
}
数组: ```java
public class MyCircularDeque {
// 1、不用设计成动态数组,使用静态数组即可
// 2、设计 head 和 tail 指针变量
// 3、head == tail 成立的时候表示队列为空
// 4、tail + 1 == head 表示为满
// 5、注意做减法指针可能变成负数 可以用 (tail - 1 + capacity ) % capacity 来做tail移位
private final int capacity;
private final int[] arr;
private int head;
private int tail;
public MyCircularDeque(int k) {
// 多存一个用于区分队列满和空的情况
capacity = k + 1;
arr = new int[capacity];
head = 0;
tail = 0;
}
public boolean insertFront(int value) {
if (isFull()) {
return false;
}
head = (head - 1 + capacity) % capacity;
arr[head] = value;
return true;
}
public boolean insertLast(int value) {
if (isFull()) {
return false;
}
arr[tail] = value;
tail = (tail + 1) % capacity;
return true;
}
public boolean deleteFront() {
if (isEmpty()) {
return false;
}
// front 被设计在数组的开头,所以是 +1
head = (head + 1) % capacity;
return true;
}
public boolean deleteLast() {
if (isEmpty()) {
return false;
}
// rear 被设计在数组的末尾,所以是 -1
tail = (tail - 1 + capacity) % capacity;
return true;
}
public int getFront() {
if (isEmpty()) {
return -1;
}
return arr[head];
}
public int getRear() {
if (isEmpty()) {
return -1;
}
// 当 tail 为 0 时防止数组越界才加的capacity
return arr[(tail - 1 + capacity) % capacity];
}
public boolean isEmpty() {
return head == tail;
}
public boolean isFull() {
// 注意:这个设计是非常经典的做法
return (tail + 1) % capacity == head;
}
}
<a name="qF8oM"></a>
### 1.2 滑动窗口最大值(239)
- 直接循环O(n^2)
```java
public int[] maxSlidingWindow(int[] nums, int k) {
int[] resultArr = new int[nums.length - k + 1];
for (int i = 0; i < nums.length - k + 1; i++) {
int max = nums[i];
for (int j = i; j < i + k; j++) {
max = Math.max(max, nums[j]);
}
resultArr[i] = max;
}
return resultArr;
}
-
1.3 层次遍历二叉树(102)
-
2. 栈
2.1 最小栈(155)
class MinStack {
Deque<Integer> stack;
Deque<Integer> minStack;
public MinStack() {
stack = new LinkedList<Integer>();
minStack = new LinkedList<Integer>();
minStack.push(Integer.MAX_VALUE);
}
public void push(int x) {
stack.push(x);
minStack.push(Math.min(minStack.peek(), x));
}
public void pop() {
stack.pop();
minStack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
2.2 删除链表第N个元素
解法一:栈,pop出 n+1个元素
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyHead = new ListNode(0, head);
ListNode temp = dummyHead;
Stack<ListNode> stack = new Stack<>();
while (null != temp) {
stack.push(temp);
temp = temp.next;
}
ListNode prev = stack.pop();
for (int i = 0; i < n; i++) {
prev = stack.pop();
}
if (prev.next != null) {
prev.next = prev.next.next;
}
return dummyHead.next;
}
-
2.3 有效括号(20)
解法一:用栈
public boolean isValid(String s) {
if (s.length() % 2 == 1) {
return false;
}
Map<Character, Character> map = new HashMap<>();
map.put('(', ')');
map.put('[', ']');
map.put('{', '}');
Stack<Character> stack = new Stack<>();
char[] charArr = s.toCharArray();
for (char c : charArr) {
if (map.containsKey(c)) {
stack.push(c);
continue;
}
if (stack.isEmpty()) {
return false;
}
Character temp = stack.pop();
if (!map.get(temp).equals(c)) {
return false;
}
}
return stack.isEmpty();
}
2.4 接雨水(42)hard
解法一:栈 ```java public int trap(int[] height) {
Deque<Integer> stack = new LinkedList<Integer>();
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;
}
```
单调栈关注一下
序号 题目 题解
42. 接雨水(困难) 暴力解法、优化、双指针、单调栈
739. 每日温度(中等) 暴力解法 + 单调栈
496. 下一个更大元素 I(简单) 暴力解法、单调栈
316. 去除重复字母(困难) 栈 + 哨兵技巧(Java、C++、Python)
901. 股票价格跨度(中等) 「力扣」第 901 题:股票价格跨度(单调栈)
402. 移掉K位数字
581. 最短无序连续子数组