直驱技术赋能手机盖板精密装配:破解工艺瓶颈,提升智造水平
2026/4/1 15:01:39
单调栈(Monotonic Stack)本质上就是**“带约束的栈”:
在任何时刻,栈内元素都保持单调递增或单调递减**的顺序。一旦新元素破坏这个单调性,就不断出栈,直到恢复单调为止。
很多问题的核心是这类需求:
对每个元素,快速找到它左边/右边第一个比它大或小的元素
比如:
如果暴力做:
每个元素向左/右扫描,时间复杂度是O(n²)
单调栈的价值在于:
把这类问题统一降到 O(n)
单调栈始终维护一个顺序不被破坏的栈结构:
关键不是“递增/递减”本身,而是:
栈里留下的,都是“还没找到答案”的元素
一旦某个新元素能“解决”栈顶元素的问题,
栈顶就该出栈了。
这是单调栈最容易被误解、但最重要的一点。
每个元素:
- 最多入栈一次
- 最多出栈一次
所以:
哪怕有while循环,也不会爆。
这点非常关键,很多人会混淆。
需要算距离、区间、面积时必须用下标
比如:
实战中90% 都是存下标
| 目标 | 栈类型 | 扫描方向 |
|---|---|---|
| 右侧第一个更大 | 单调递减 | 左 → 右 |
| 右侧第一个更小 | 单调递增 | 左 → 右 |
| 左侧第一个更大 | 单调递减 | 右 → 左 |
| 左侧第一个更小 | 单调递增 | 右 → 左 |
一句口诀:
找「更大」用递减栈,找「更小」用递增栈
你可以把单调栈理解为:
一种“延迟决策”的结构
栈中始终保存的是:
看到这些关键词,条件反射就对了:
好,这里给你一组单调栈必刷经典题清单,我会按「题目 → 思路 → 单调栈过程 → 答案实现」完整走一遍。
从入门 → 核心 → 进阶,基本覆盖 90% 面试/竞赛场景。
给定数组nums,返回一个数组res,res[i]是nums[i]右边第一个比它大的元素,没有则为-1。
输入: [2,1,2,4,3] 输出: [4,2,4,-1,-1]nums = [2,1,2,4,3] i=0: stack=[0] i=1: stack=[0,1] i=2: nums[2]=2 > nums[1]=1 → pop 1 → res[1]=2 stack=[0,2] i=3: 4 > 2 → pop 2 → res[2]=4 4 > 2 → pop 0 → res[0]=4 stack=[3] i=4: stack=[3,4]defnext_greater(nums):n=len(nums)res=[