识别信号:"下一个更大/更小"、"接雨水"、"最大矩形"、"区间最值贡献"。
口诀:求大用减、求小用增(栈内单调性)。栈里存索引。
弹栈瞬间三信息同时到手:被弹元素(高)、新栈顶(左边界)、当前 i(右边界)。三类题共用这骨架,区别只在结算公式。

单调栈for 遍历数组,每轮两个动作:
- 弹栈(while):当前元素破坏单调性时,不停弹出栈顶。弹栈时拿到三样东西:
- 被弹元素(
stack.pop()) - 左边界(弹完后
stack.peek()) - 右边界(当前
i)。
- 被弹元素(
- 压栈:当前索引入栈,继续维持单调性。
代码模板:
java
Deque<Integer> stack = new ArrayDeque<>();for (int i = 0; i < n; i++) { while (!stack.isEmpty() && nums[i] 【条件比较】 nums[stack.peek()]) { int popped = stack.pop(); // 被弹元素 int L = stack.isEmpty() ? -1 : stack.peek(); // 左边界 // 右边界 = i,在此结算 } stack.push(i);}1、 下一个更大元素
java
int n = nums.length;int[] ans = new int[n];Arrays.fill(ans, -1);Deque<Integer> stack = new ArrayDeque<>(); // 存索引,栈内对应值单调递减for (int i = 0; i < n; i++) { while (!stack.isEmpty() && nums[i] > nums[stack.peek()]) { ans[stack.pop()] = nums[i]; } stack.push(i);}
>严格大于 → 严格下一个更大。要「大于等于」改>=。这个符号是唯一需要按题调整的地方。
2、 接雨水
java
int trap(int[] height) { Deque<Integer> stack = new ArrayDeque<>(); int water = 0; for (int i = 0; i < height.length; i++) { while (!stack.isEmpty() && height[i] > height[stack.peek()]) { int bot = stack.pop(); // 凹槽底部 if (stack.isEmpty()) break; // 左边没墙,接不住 int L = stack.peek(); // 左墙 int w = i - L - 1; // 宽度 int bounded = Math.min(height[L], height[i]) - height[bot]; water += w * bounded; } stack.push(i); } return water;}
if (stack.isEmpty()) break必须写——弹完栈空说明左边没更高柱子,水从左边流走。漏掉会在stack.peek()处 NPE。
3、柱状图最大矩形(哨兵技巧)
java
int largestRectangle(int[] heights) { int n = heights.length; int[] h = new int[n + 2]; // 首尾哨兵 0 System.arraycopy(heights, 0, h, 1, n); Deque<Integer> stack = new ArrayDeque<>(); int ans = 0; for (int i = 0; i < h.length; i++) { while (!stack.isEmpty() && h[i] < h[stack.peek()]) { int top = stack.pop(); ans = Math.max(ans, h[top] * (i - stack.peek() - 1)); } stack.push(i); } return ans;}注意这是
h[i] < h[stack.peek()](求小用增)。首哨兵保证stack.peek()永不为空;尾哨兵逼出栈内所有元素。System.arraycopy目标偏移是 1,不是 0。
本文由 AgentPlanFlow 生成