单调栈(Monotonic Stack)

单调栈是一种在O(n)复杂度下解决NextGreaterElement问题的数据结构,它维护一个单调递减的栈,用于寻找序列中每个元素后面的第一个更大元素。在遍历过程中,新元素与栈顶元素比较,若新元素更大,则更新栈顶元素的NGE并继续比较,否则将新元素压入栈。案例展示了如何找到数组中每个元素后面的第一个大于它的元素,如果没有则返回-1。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单调栈是一种和单调队列类似的数据结构。单调队列主要在 O ( n ) O(n) O(n)复杂度下解决滑动窗口问题,单调栈主要在 O ( n ) O(n) O(n)复杂度下解决Next Greater Element(NGE)问题(对序列中的每个元素找下一个/上一个比他大/小的元素)

基本思想

单调栈维护一个,表示“待确定NGE的元素”,然后遍历序列。当碰上一个新元素,越靠近栈顶的元素离新元素的位置越近。所以不断比较新元素与栈顶,如果新元素比栈顶大,则可断定新元素就是栈顶的NGE,于是弹出栈顶并继续比较。直到新元素不比栈顶大,再将新元素压入栈。显然,这样形成的栈是单调递减的。

案例

举个例子,寻找数列中第 i i i个元素之后第一个大于它的元素值(没有则返回-1):

数组结果说明
10 3 7 4 12初始化
10 3 7 4 1210(索引:0)- i = 0 i=0 i=0时,栈空,则10入栈
10 3 7 4 1210 3(索引:0 1)- - i = 1 i=1 i=1时,10大于3,则3入栈
10 3 7 4 1210 7(索引:0 2)- 7 - i = 2 i=2 i=2时,3小于7,则3出栈,结果数组中索引1位置标记为7,7入栈
10 3 7 4 1210 7 4(索引:0 2 3)- 7 - - i = 3 i=3 i=3时,7大于4,则4入栈
10 3 7 4 1212(索引:4)12 7 12 12 - i = 4 i=4 i=4时,12大于4,12大于7,12大于10,结果数组中索引0、2、3位置标记为12,12入栈
10 3 7 4 1212 7 12 12 -1由于在 i = 4 i=4 i=4之后没有大于12的元素,所以返回-1

其的核心代码为:

public class Template {
    public void template(int[] nums) {
        int n = nums.length;
        int[] ans = new int[n];
        Stack<Integer> s = new Stack<>();

        for (int i = 0; i < n; i++) {
            if (!s.isEmpty()) {
                while (!s.isEmpty() && nums[s.peek()] < nums[i]) {
                    ans[s.pop()] = nums[i];
                }
            }
            s.push(i);
        }
        while (!s.isEmpty()) ans[s.pop()] = -1;
        for (int a : ans) System.out.printf("%d ", a);
    }

    public static void main(String[] args) {
        Template template = new Template();
        template.template(new int[]{10, 3, 7, 4, 12});
    }
}

题目链接

  1. 2289. 使数组按非递减顺序排列

参考文献:

  1. 单调栈
  2. 【模板】单调栈,上面的题目和该题目返回的结果不一致,该题返回的时索引,上题返回的是数值
### 单调栈算法及其应用 单调栈是一种特殊的栈结构,其核心特点是栈内的元素保持单调递增或单调递减的顺序[^2]。这种数据结构在处理涉及比较相邻元素大小的问题时非常高效。以下将详细介绍单调栈的基本实现方法以及常见的应用场景。 #### 单调栈的基本实现 单调栈的实现通常基于普通栈,但需要满足单调性条件。具体来说,在向栈中插入新元素时,需要检查栈顶元素是否破坏了单调性。如果破坏,则需要弹出栈顶元素直到恢复单调性为止[^1]。 以下是单调递减栈的一个简单实现示例: ```python def build_monotonic_stack(arr): stack = [] result = [] for num in arr: # 弹出所有小于当前元素的栈顶元素 while stack and stack[-1] < num: stack.pop() # 将当前元素压入栈 stack.append(num) # 记录栈的状态(可选) result.append(stack.copy()) return result ``` #### 单调栈的应用场景 单调栈适用于解决一系列与“最近”相关的经典问题,例如: 1. **寻找最近的更大/更小元素** 单调栈可以用于快速找到某个元素左边或右边第一个比它大或小的元素。这类问题在股票价格波动、柱状图最大矩形面积等问题中十分常见。 2. **删除重复字母且字典序最小** 在字符串处理领域,单调栈可以帮助筛选出符合特定条件的字符组合。例如,通过单调栈可以实现删除重复字母后生成字典序最小的字符串[^3]。 3. **最大二叉树** 单调栈可用于构造最大二叉树,其中每个节点的值为其子节点的最大值。通过维护一个单调递减栈,可以快速确定每个节点的父节点关系[^3]。 4. **柱状图中的最大矩形面积** 给定一个由非负整数组成的高度数组,使用单调栈可以在 O(n) 时间复杂度内计算柱状图中的最大矩形面积[^4]。以下是一个具体的实现代码: ```python def largest_rectangle_area(heights): stack = [] max_area = 0 heights.append(0) # 添加哨兵,确保栈最终清空 for i, h in enumerate(heights): while stack and heights[stack[-1]] > h: height = heights[stack.pop()] width = i if not stack else i - stack[-1] - 1 max_area = max(max_area, height * width) stack.append(i) return max_area ``` #### 总结 单调栈是一种高效的算法工具,尤其适合处理涉及比较相邻元素大小的问题。通过合理利用单调栈的特性,可以显著降低时间复杂度并提高程序性能[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值