引言
栈和队列是两种基本的线性数据结构,在算法和系统设计中应用广泛。本文系统讲解栈和队列的原理和经典问题。
一、栈(Stack)
1.1 栈的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class Stack<T> { private Object[] data; private int top; private static final int DEFAULT_CAPACITY = 10; public Stack() { data = new Object[DEFAULT_CAPACITY]; top = -1; } public void push(T item) { if (top == data.length - 1) { resize(); } data[++top] = item; } @SuppressWarnings("unchecked") public T pop() { if (isEmpty()) { throw new EmptyStackException(); } return (T) data[top--]; } @SuppressWarnings("unchecked") public T peek() { if (isEmpty()) { throw new EmptyStackException(); } return (T) data[top]; } public boolean isEmpty() { return top == -1; } private void resize() { data = Arrays.copyOf(data, data.length * 2); } }
|
1.2 有效的括号(LeetCode 20)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public boolean isValid(String s) { Stack<Character> stack = new Stack<>(); Map<Character, Character> map = new HashMap<>(); map.put(')', '('); map.put('}', '{'); map.put(']', '['); for (char c : s.toCharArray()) { if (map.containsKey(c)) { if (stack.isEmpty() || stack.pop() != map.get(c)) { return false; } } else { stack.push(c); } } return stack.isEmpty(); }
|
1.3 最小栈(LeetCode 155)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class MinStack { private Stack<Integer> stack; private Stack<Integer> minStack; public MinStack() { stack = new Stack<>(); minStack = new Stack<>(); } public void push(int val) { stack.push(val); if (minStack.isEmpty() || val <= minStack.peek()) { minStack.push(val); } } public void pop() { int val = stack.pop(); if (val == minStack.peek()) { minStack.pop(); } } public int top() { return stack.peek(); } public int getMin() { return minStack.peek(); } }
|
二、队列(Queue)
2.1 队列实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public class Queue<T> { private Object[] data; private int front; private int rear; private int size; private static final int DEFAULT_CAPACITY = 10; public Queue() { data = new Object[DEFAULT_CAPACITY]; front = 0; rear = -1; size = 0; } public void offer(T item) { if (size == data.length) { resize(); } rear = (rear + 1) % data.length; data[rear] = item; size++; } @SuppressWarnings("unchecked") public T poll() { if (isEmpty()) { throw new NoSuchElementException(); } T item = (T) data[front]; front = (front + 1) % data.length; size--; return item; } public boolean isEmpty() { return size == 0; } private void resize() { Object[] newData = new Object[data.length * 2]; for (int i = 0; i < size; i++) { newData[i] = data[(front + i) % data.length]; } data = newData; front = 0; rear = size - 1; } }
|
2.2 用栈实现队列(LeetCode 232)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class MyQueue { private Stack<Integer> input; private Stack<Integer> output; public MyQueue() { input = new Stack<>(); output = new Stack<>(); } public void push(int x) { input.push(x); } public int pop() { peek(); return output.pop(); } public int peek() { if (output.isEmpty()) { while (!input.isEmpty()) { output.push(input.pop()); } } return output.peek(); } public boolean empty() { return input.isEmpty() && output.isEmpty(); } }
|
三、单调栈
3.1 每日温度(LeetCode 739)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public int[] dailyTemperatures(int[] temperatures) { int n = temperatures.length; int[] result = new int[n]; Stack<Integer> stack = new Stack<>(); for (int i = 0; i < n; i++) { while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) { int prevIndex = stack.pop(); result[prevIndex] = i - prevIndex; } stack.push(i); } return result; }
|
四、优先队列
4.1 前K个高频元素(LeetCode 347)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public int[] topKFrequent(int[] nums, int k) { Map<Integer, Integer> count = new HashMap<>(); for (int num : nums) { count.put(num, count.getOrDefault(num, 0) + 1); } PriorityQueue<Integer> heap = new PriorityQueue<>( (a, b) -> count.get(a) - count.get(b) ); for (int num : count.keySet()) { heap.offer(num); if (heap.size() > k) { heap.poll(); } } int[] result = new int[k]; for (int i = 0; i < k; i++) { result[i] = heap.poll(); } return result; }
|
总结
栈和队列核心:
- 栈:后进先出(LIFO)
- 队列:先进先出(FIFO)
- 单调栈:维护单调性
- 优先队列:堆实现
参考资料