📘 教案 08:单调栈(Monotonic Stack)
1️⃣ 先看一个真实问题(非常关键)
给你一个数组:
text
[2, 1, 2, 4, 3]
问题:
对每个数,找到"右边第一个比它大的数"
手算一下(你脑子会这样想)
- 2 → 右边第一个更大是 4
- 1 → 右边第一个更大是 2
- 2 → 右边第一个更大是 4
- 4 → 没有 → -1
- 3 → 没有 → -1
如果你写代码(暴力)
python
for i in range(n):
for j in range(i+1, n):
if A[j] > A[i]:
break
👉 时间复杂度:
O(n2)\]\[ O(n\^2) \]\[O(n2)
❗问题本质
你在重复做一件事:
"找右边第一个更大元素"
2️⃣ 单调栈就是为了解决这个
一句话:
单调栈 = 用一个"有序结构",避免重复比较
3️⃣ 核心直觉(最重要)
我们从左往右扫数组:
text
[2, 1, 2, 4, 3]
我们维护一个东西:
👉 一个"还没找到答案的元素集合"
4️⃣ 一步一步看(这是核心)
Step 1:看 2
text
stack = [2]
👉 还不知道右边谁比它大
Step 2:看 1
text
stack = [2, 1]
👉 1 也没找到更大的
Step 3:看 2
来了关键点👇
👉 当前 2 > 栈顶 1
说明:
text
1 的答案找到了 → 就是 2
👉 把 1 弹出去
现在继续:
text
stack = [2]
当前 2 == 栈顶 2 → 不弹
text
stack = [2, 2]
Step 4:看 4(高潮)
👉 4 > 2 → 弹
👉 4 > 2 → 再弹
text
2 → 4
2 → 4
👉 全部解决
text
stack = []
然后:
text
stack = [4]
Step 5:看 3
text
stack = [4, 3]
最后
栈里剩下的:
text
4, 3
👉 没有更大的 → -1
🔥 到这里核心已经懂了
谁被弹出,谁的答案就确定了
5️⃣ 单调栈到底是什么?
现在给定义(你已经能理解了)
定义:
一个"保持单调性"的栈结构
两种类型:
🔹 单调递减栈(常用)
栈内从底到顶:
text
大 → 小
👉 用来找:
右边第一个更大元素
🔹 单调递增栈
text
小 → 大
👉 用来找:
右边第一个更小元素
6️⃣ 标准模板(你可以直接教人)
找"右边第一个更大"
python
stack = []
res = [-1]*n
for i in range(n):
while stack and A[i] > A[stack[-1]]:
idx = stack.pop()
res[idx] = A[i]
stack.append(i)
注意:
👉 栈里存的是"下标",不是值
7️⃣ 为什么一定是 O(n)
关键:
每个元素只会:
- 入栈一次
- 出栈一次
👉 总操作:
O(n)\]\[ O(n) \]\[O(n)
8️⃣ 常见应用(非常重要)
8.1 下一个更大元素
👉 刚讲的
8.2 柱状图最大矩形(经典难题)
8.3 股票问题
👉 找最近更大/更小
8.4 温度问题(LeetCode经典)
9️⃣ 单调栈最本质一句话
它不是"栈",而是"用栈维护顺序关系"
10️⃣ 常见错误
❌ 错误1:搞不清什么时候弹
记住一句:
👉 当前元素更强(更大/更小) → 弹栈
❌ 错误2:存值还是下标
👉 一律存下标
❌ 错误3:方向搞反
- 左 → 右
- 右 → 左
答案不同
教学总结
单调栈的本质是:
用一个"有序结构"一次性解决所有"下一个更大/更小"的问题