单调栈解决“下一个更大元素”问题的核心是用list模拟栈并维护严格递减序列,遍历时入栈前弹出所有破坏单调性的元素;栈中存索引以更新结果位置,比较需用nums[i] > nums[stack[-1]],循环数组通过索引取模与2n−1次遍历处理,时间复杂度O(n)。

单调栈解决“下一个更大元素”问题,核心在于用栈维护一个递减序列,让每个元素在入栈前,先把所有比它小的栈顶元素“处理掉”——也就是确认它们的下一个更大值就是当前元素。
为什么用单调递减栈
目标是找每个数右边第一个比它大的数。如果栈从底到顶保持递减,那栈顶就是当前看到的最小值;一旦遇到更大的数,它就一定是栈顶元素的“答案”,因为它是栈顶右边第一个更大的数。
- 栈里存的是原始索引(不是数值),这样才能更新结果数组对应位置
- 比较时必须用 nums[i] > nums[stack[-1]],而不是和索引比大小
- while 条件顺序不能错:先判 stack 非空,再取 stack[-1],否则空栈会报错
标准单次遍历写法
适用于普通数组(非循环):
- 初始化 result = [-1] * n,栈为空列表
- 从左到右遍历每个索引 i
- 只要栈非空且 nums[i] > nums[stack[-1]],就弹出栈顶 idx,并设 result[idx] = nums[i]
- 把当前 i 压入栈
每个索引最多进出栈一次,时间复杂度稳定 O(n)。
处理循环数组的技巧
比如 [1,2,1] 中最后一个 1 的答案是 2(要绕回开头找):
- 不真正拼接数组(省空间),而是用 i % n 模拟循环索引
- 遍历范围设为 0 到 2*n - 1,确保每个元素都有机会被“回头看”
- 靠 result 初始化为 -1 自动防重复赋值:只有第一次弹出时才更新
注意常见错误
容易卡住的地方其实很集中:
- 存数值而非索引 → 找不到该填到 result 哪个位置
- while 条件写成 nums[i] > stack[-1] → 实际在比索引和数值,逻辑全乱
- 弹出条件反了(比如写成 <=)→ 维护成了递增栈,解决的是“下一个更小元素”
- 没检查栈是否为空就取 stack[-1] → 程序直接崩溃


















