手撕力扣之栈:下一个更大元素 I、下一个更大元素 II、132 模式、和至少为 K 的最短子数组

本文介绍了如何利用栈解决LeetCode中的几个问题:496. 下一个更大元素 I,503. 下一个更大元素 II,456. 132 模式,以及862. 和至少为 K 的最短子数组。通过创建单调栈或哈希表,分别找到元素的下一个更大元素、在循环数组中的下一个更大元素、132模式的存在性和和至少为K的最短子数组。

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

力扣496. 下一个更大元素 I
给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出-1。
思路:
创建一个临时栈,一个哈希表,然后遍历 nums2nums2。
若当前栈无数据,则当前数字入栈备用。
若当前栈有数据,则用当前数字与栈顶比较:
3.1 当前数字 > 栈顶,代表栈顶对应下一个更大的数字就是当前数字,则将该组数字对应关系,记录到哈希表。
3.2 当前数字 < 栈顶,当前数字压入栈,供后续数字判断使用。
这样,我们就可以看到哈希表中存在部分 nums2nums2 数字的对应关系了,而栈中留下的数字,代表无下一个更大的数字,我们全部赋值为 -1−1 ,然后存入哈希表即可。
遍历 nums1nums1,直接询问哈希表拿对应关系即可。

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        stack<int>s;
        unordered_map<int,int>num_map;
        int size = nums1.size();
        vector<int>vec_num;
        for(int i = 0;i < nums2.size();++i)
        {
            while(!s.empty() && nums2[i]>s.top())
            {
                num_map[s.top()] = nums2[i];
                s.pop();
            }
            s.push(nums2[i]);
        }
        while(!s.empty())
        {
            num_map[s.top()] = -1;
            s.pop();
        }
        for(int i = 0;i<size;++i)
        {
            vec_num.push_back(num_map[nums1[i]]);
        }
        return vec_num;
    }
};

作者:demigodliu
链接:https://leetcode-cn.com/problems/next-greater-element-i/solution/zhan-xia-yi-ge-geng-da-yuan-su-i-by-demi-cumj/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

力扣503. 下一个更大元素 II
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
思路:
讲两个nums数组拼接在一起,使用单调栈计算出每一个元素的下一个最大值,最后再把结果集即result数组resize到原数组大小就可以了。

// 版本二
class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        vector<int> result(nums.size(), -1);
        if (nums.size() == 0) return result;
        stack<int> st;
        for (int i = 0; i < nums.size() * 2; i++) { 
            // 模拟遍历两边nums,注意一下都是用i % nums.size()来操作
            while (!st.empty() && nums[i % nums.size()] > nums[st.top()]) {
                result[st.top()] = nums[i % nums.size()];
                st.pop();
            }
            st.push(i % nums.size());
        }
        return result;
    }
};

作者:carlsun-2
链接:https://leetcode-cn.com/problems/next-greater-element-ii/solution/503-xia-yi-ge-geng-da-yuan-su-iidan-diao-9ez5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

力扣456. 132 模式
给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。
思路:
枚举到 2:栈内元素为 [2],k = INF
枚举到 4:不满足「单调递减」,2 出栈更新 k,4 入栈。栈内元素为 [4],k = 2
枚举到 1:满足 nums[i] < k,说明对于 i 而言,后面有一个比其大的元素(满足 i < k 的条件),同时这个 k 的来源又是因为维护「单调递减」而弹出导致被更新的(满足 i 和 k 之间,有比 k 要大的元素)。因此我们找到了满足 132 结构的组合。

class Solution {
public:
    bool find132pattern(vector<int>& nums) {
        stack<int> st;
        int n = nums.size(), k = INT_MIN;
        for(int i = n - 1; i >= 0; i--){
            if(nums[i] < k) return true;
            while(!st.empty() and st.top() < nums[i]) { 
                k = max(k,st.top()); st.pop();
            }
            st.push(nums[i]);
        }
        return false;
    }
};

作者:AC_OIer
链接:https://leetcode-cn.com/problems/132-pattern/solution/xiang-xin-ke-xue-xi-lie-xiang-jie-wei-he-95gt/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

力扣862. 和至少为 K 的最短子数组
返回 A 的最短的非空连续子数组的长度,该子数组的和至少为 K 。
如果没有和至少为 K 的非空子数组,返回 -1 。
思路:
一个双端单调队列:如果新加入的数比队列尾的数小,那么队列尾的数就可以丢去,这是因为如果未来的一个数能和队列尾的数满足条件,那么也一定可以和新加入的数满足条件。 另外,如果一个数和队列头的数已经满足了条件,那么队列头的数就不用保留了,这是因为以后加入的数,就算能和队列头的数满足条件,也会比现在的长度大。

class Solution {
public:
    int shortestSubarray(vector<int>& A, int K) {
        
        int n = A.size();
        vector<long> sum(n+1, 0);
        
        for(int i = 0; i < n; i++) //准备工作
            sum[i+1] = sum[i] + A[i];
        
        deque<int> de;
        int j = 0;
        int res = n+1;
        
        while(j<=n){
            
            while(!de.empty() && sum[j] <= sum[de.back()]){ 
                de.pop_back();
            }
            while(!de.empty() && sum[j] - sum[de.front()] >= K){ 
                res = min( res, j - de.front());
                de.pop_front();
            }
            de.push_back(j); //最后才坐下去
            j++;
        }
        if(res == n+1)
            return -1;
        else
            return res;
    }
};

作者:ka-pei-qing-jia-wu-shao-tang
链接:https://leetcode-cn.com/problems/shortest-subarray-with-sum-at-least-k/solution/he-guan-fang-yi-yang-de-jie-fa-zi-ji-de-yi-dian-di/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值