单调栈解决 Next Greater Element模型问题

文章介绍了如何使用Java中的栈数据结构解决两个问题:NextNumber问题,即找到数组中每个元素右边比它大的最近一个元素;132模式,判断给定数组是否存在132模式的子序列。通过栈实现的算法可以有效地降低时间复杂度,提高效率。

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

前言

栈(stack)是一个十分常见与简单的数据结构,讲究先进后出。

Java中栈的方法有
push() 将元素放入栈顶
pop() 将栈顶元素推出栈
peek() 查看栈顶元素
isEmpty() 判断栈是否为空 为空返回true 不为空返回false

栈常解决的问题(Next Number)

可解决问题1

给你一个数组要求你返回一个等长的数组,返回的数组中每个元素为对应之前数组比它大的最近一个元素,如果没有就返回-1,这样说可能不太明白,直接上例子

给你一个数组[2,7,1,4] 要求你返回[7,-1,4,-1]

解释:数组元素2后边比它大的第一个元素为7;7后边比它大的第一个元素没有找到为-1;1后边比它大的第一个元素是4;4后边没有比它大的元素返回为-1;

我们普遍想到的是暴力求解,O(n^2)的时间复杂的常常是超时的。

我们可以想一个这样的思路:从后往前遍历,用栈来存储当前元素右边比他大的最近一个元素。如果栈顶元素stack.peek()<=nums[i],我们就不断推栈,直到找到比nums[i]大的元素,没有找到为-1

class Solution {
    public static int[] findNextElement(int[] nums) {
        //定义一个等长的数组
        int[] result = new int[nums.length];
        Stack<Integer> stack = new Stack<>();
        for (int i = nums.length-1; i >=0 ; i--) {
            //如果栈顶元素小于当前元素就不断推栈
            while(!stack.isEmpty()&&stack.peek()<nums[i]){
                stack.pop();
            }
            result[i]=stack.isEmpty()?-1:stack.peek();
            stack.push(nums[i]);
        }
        return result;
    }
}

可解决问题2

力扣132模式(中等)

给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]nums[j]nums[k] 组成,并同时满足:i < j < knums[i] < nums[k] < nums[j]

如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false

听起来好像很简单,但实际做起来需要费一些功夫。我们参考原先模型的核心代码

        for (int i = nums.length-1; i >=0 ; i--) {
            //这里略微做了改动,stack中存放的是数组的下标索引
            while(!stack.isEmpty()&&nums[stack.peek()]<=nums[i]){
                stack.pop();
            }
            stack.push(i);
        }

我们观察当nums[stack.peek()]<=nums[i],

我们往常的思路是去除栈内比nums[i]小的数。

我们换一种思路,此时想想以下我们是不是找到了num[j]>num[k]的情况, 我们把num[i]理解为题目中要找的nums[j],把栈内推出的数理解为k ,而我们不断推出的数,最后一个为比nums[j]小的最大一个数,我们此时只需要在nums向前遍历的途中找到一个nums[i],便可满足nums[i]<nums[k]<nums[j]
    public boolean find132pattern(int[] nums) {
        //栈中存放数组的下标索引
        Stack<Integer> stack = new Stack<>();
        Integer k =-1;
        for (int i = nums.length-1; i >= 0; i--) {
            if(k!=-1&&nums[i]<nums[k])return true;
            while(!stack.isEmpty()&&nums[stack.peek()]<nums[i]){
                //此时我们找到了左边元素大于右边的情况,我们可以将
                //当前元素nums[i] 理解为题目中第一大元素3 nums[j]
                //我们推出的栈内元素 理解为题目中中等大元素2 nums[k]
                k = stack.pop();
                //现在我们只需在i向前遍历中找到nums[i]<nums[k]便可满足条件
            }
            stack.push(i);

        }
        return false;
    }
### 单调栈算法的应用及实现 单调栈是一种特殊的栈结构,其核心在于通过维护栈内元素的顺序(单调递增或单调递减),能够高效地解决问题。以下是关于单调栈的具体应用及其实现案例。 #### 应用场景 单调栈可以用于解决一系列与数组有关的问题,尤其是涉及寻找某个元素右侧或左侧第一个大于或小于该元素的位置的情况。这种问题通常可以通过暴力法求解,但时间复杂度较高;而借助单调栈,则可以在 \( O(n) \) 的时间内完成计算[^4]。 #### 实现案例分析 以下是一个具体的例子来说明如何使用单调栈解决问题: 给定一个数组 `[2, 1, 2, 4, 3]`,目标是找到每个元素右边第一个比它大的数。最终答案应为 `[4, 2, 4, -1, -1]`[^2]。 ##### Python代码实现 下面提供了一种基于单调递减栈的方法来解决上述问题: ```python def next_greater_element(nums): stack = [] # 初始化单调栈 result = [-1] * len(nums) # 默认结果均为-1 for i in range(len(nums)): while stack and nums[i] > nums[stack[-1]]: index = stack.pop() result[index] = nums[i] stack.append(i) return result nums = [2, 1, 2, 4, 3] print(next_greater_element(nums)) # 输出: [4, 2, 4, -1, -1] ``` 在这段代码中,我们初始化了一个空栈 `stack` 和默认填充 `-1` 的结果列表 `result`。遍历输入数组中的每个元素时,如果当前元素大于栈顶索引对应的值,则弹出栈顶并更新对应位置的结果,直到不再满足条件为止。最后将当前元素的索引入栈以便后续比较。 #### 关键特性解释 1. **维持单调性**: 栈始终保持一种特定的顺序——要么是从底到顶递增,要么是从底到顶递减。这取决于所要解决的实际问题需求[^3]。 2. **线性时间复杂度**: 借助于一次完整的数组扫描以及合理的进出栈操作,整个过程仅需 \( O(n) \)。 #### 总结 通过对单调栈的理解和运用,我们可以优雅且高效地处理许多看似复杂的数组查询类题目。这种方法不仅简化了逻辑流程,还极大地提升了程序运行效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值