单调栈的定义与类型
单调栈是一种栈结构,内部元素保持严格的单调递增或单调递减顺序。
分为两种基本类型:
- 单调递增栈:栈底到栈顶元素逐渐增大
- 单调递减栈:栈底到栈顶元素逐渐减小
核心原理与典型应用
在遍历数组时,利用栈来记录尚未找到"下一个更大/更小"元素的下标。当遇到一个破坏单调性的元素时,就依次弹出栈内元素,并当场结算这些弹出元素的答案。
主要解决两类问题:
-
寻找数组中每个元素 左边/右边 第一个比它 大/小 的元素。
-
计算特定几何结构的极值(如凹槽面积、矩形面积)
基础代码模板
右侧第一个更大元素
java
public int[] nextGreaterElement(int[] nums) {
int n = nums.length;
int[] res = new int[n];
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && nums[i] > nums[stack.peek()]) {
int idx = stack.pop();
res[idx] = nums[i];
}
stack.push(i);
}
while (!stack.isEmpty()) {
res[stack.pop()] = -1;
}
return res;
}
右侧第一个更小元素 仅需修改比较符号:
java
while (!stack.isEmpty() && nums[i] < nums[stack.peek()]) {
// 处理逻辑
}
经典问题解析
接雨水问题(LeetCode 42)
思路 :按列求雨水。使用单调递减栈(栈底最大),当 height[i] > height[stack.peek()] 时形成凹槽:
-
弹出
bottom作为底部。 -
若栈空则无法蓄水,否则
left = stack.peek()为左边界。 -
宽度 =
i - left - 1。 -
高度 =
min(height[left], height[i]) - height[bottom]。
java
public int trap(int[] height) {
Deque<Integer> stack = new ArrayDeque<>();
int res = 0;
for (int i = 0; i < height.length; i++) {
while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
int bottom = stack.pop();
if (stack.isEmpty()) break;
int left = stack.peek();
int w = i - left - 1;
int h = Math.min(height[left], height[i]) - height[bottom];
res += w * h;
}
stack.push(i);
}
return res;
}
最大矩形问题(LeetCode 84)
思路 :寻找每个柱子左右两边第一个比它矮的柱子,宽度 = right - left - 1,高度 = heights[i]。
使用单调递增栈(栈底最小),当 heights[i] < heights[stack.peek()] 时触发
java
public int largestRectangleArea(int[] heights) {
int n = heights.length;
int[] newHeights = new int[n + 2]; // 哨兵技巧,避免越界
System.arraycopy(heights, 0, newHeights, 1, n);
Deque<Integer> stack = new ArrayDeque<>();
int res = 0;
for (int i = 0; i < newHeights.length; i++) {
while (!stack.isEmpty() && newHeights[i] < newHeights[stack.peek()]) {
int h = newHeights[stack.pop()];
int left = stack.peek();
int w = i - left - 1;
res = Math.max(res, h * w);
}
stack.push(i);
}
return res;
}
时间复杂度与空间复杂度
- 时间复杂度:O(n),每个元素仅入栈出栈一次
- 空间复杂度:O(n),栈的存储开销
关键注意事项
- 下标存储优于值存储,便于计算宽度
- 比较条件选择(严格单调/非严格单调)需根据题意调整
- 推荐使用
ArrayDeque代替传统Stack类