2022-2-10 LeetCode 单调栈

这篇博客介绍了如何使用单调栈解决一系列数组相关的问题,包括每日温度、寻找数组中的下一个更大元素以及在循环数组中找到下一个更大元素。博主详细解析了算法思路,包括如何寻找左侧或右侧的第一个大于当前元素的值,并提供了具体的代码实现。此外,还探讨了接雨水和柱状图中最大矩形的问题,同样利用单调栈和寻找特定点两侧高度的方法来求解。
摘要由CSDN通过智能技术生成

模版题1 纯模版

739. 每日温度

请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例 1:

输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]

单调栈:用来寻找序列中一个元素左边/右边第一个比自身大/小的元素。
比如题目要寻找比自身大的第一个元素,栈底到顶由大到小。因为栈顶遇到一个 比自己大的元素就可以弹出,记录信息。

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        int n=temperatures.size();
        vector<int> res(n,0);
        stack<int> s;

        for(int i=0;i<n;i++){
            if(s.empty()){
                s.push(i);
                continue;
            }
            if(temperatures[i]<=temperatures[s.top()]){
                s.push(i);
            }
            else{
                while(!s.empty()&&temperatures[i]>temperatures[s.top()]){
                    int k=s.top();
                    s.pop();
                    res[k]=i-k;
                }
                s.push(i);
            }
        }
        return res;

    }
};

496. 下一个更大元素 I

nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。

给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。

对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。

返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。

相比上一题多了个hash…
我的方法的大部分还是和上题保持一致,但是输出的时候要注意映射关系。

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        int n=nums1.size();
        int m=nums2.size();
        vector<int> t(m,-1);
        vector<int> res(n,-1);
        unordered_map<int,int> mp;
        stack<int> s;
        s.push(0);
        for(int i=1;i<m;i++){
            if(nums2[i]<=nums2[s.top()]){
                s.push(i);
            }
            else{
                while(!s.empty()&&nums2[i]>nums2[s.top()]){
                   // cout<<nums2[i]<<" "<<nums2[s.top()]<<endl;
                    t[s.top()]=i;
                    s.pop();
                    
                }
                s.push(i);
            }
        }

        for(int i=0;i<m;i++){
            if(t[i]!=-1) mp[nums2[i]]=nums2[t[i]];
            else mp[nums2[i]]=-1;
       //     cout<<nums2[i]<<t[i]<<endl;
        }

        for(int i=0;i<n;i++){
            res[i]=mp[nums1[i]];
        }

        return res;

    }
};

503. 下一个更大元素 II(循环数组 下标取模)

给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。

数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。

示例 1:

输入: nums = [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        int n=nums.size();
        vector<int> res(n,-1);
        stack<int> s;
        s.push(0);
        for(int i=1;i<2*n;i++){
            if(nums[i%n]<=nums[s.top()]){
                s.push(i%n);
            }
            else{
                while(!s.empty()&&nums[i%n]>nums[s.top()]){
                    res[s.top()]=nums[i%n];
                    s.pop();
                }
                s.push(i%n);
            }
        }
        return res;

    }
};

模版题2 (找一个点两遍低的,两边高的)

42. 接雨水

法1:按列计算雨水

class Solution {
public:
    int trap(vector<int>& height) {
        //第一种方法,按列计算
        int n=height.size();
        vector<int> leftHeight(n,0);
        vector<int> rightHeight(n,0);
        int res=0;
        for(int i=1;i<n;i++){
            leftHeight[i]=max(leftHeight[i-1],height[i-1]);
            
        }
        for(int i=n-2;i>=0;i--){
            rightHeight[i]=max(rightHeight[i+1],height[i+1]);
            //cout<<rightHeight[i]<<" "<<endl;
        }

        for(int i=1;i<n-1;i++){
            if(height[i]<leftHeight[i]&&height[i]<rightHeight[i]){
                res+=min(leftHeight[i],rightHeight[i])-height[i];
            }
        }

        return res;
    }
};

法2:按行计算雨水(利用单调栈)

class Solution {
public:
    int trap(vector<int>& height) {
        int n=height.size();
        stack<int> s;
        int res=0;
        
        s.push(0);
        for(int i=1;i<n;i++){
            if(height[i]<=height[s.top()]){
                s.push(i);
            }
            else{
                while(!s.empty()&&height[i]>height[s.top()]){
                    int mid=s.top();
                    s.pop();
                    if(!s.empty()){
                        int h=min(height[i],height[s.top()])-height[mid];
                        int w=i-s.top()-1;
                        res+=w*h;
                    }
                }
                s.push(i);
            }
        }

    
    return res;

    }
};

84. 柱状图中的最大矩形

关键在于找到三个变量:
mid=s.top()

s.pop()

left=s.top();
right=i;

然后计算要求的面积:w*h
注意:w,h是需要分析的点。
w=right-left-1
h=heigh[mid]

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        heights.insert(heights.begin(), 0); // 数组头部加入元素0
        heights.push_back(0); // 数组尾部加入元素0
        int n=heights.size();
        int res=0;
        stack<int> s;
        s.push(0);
        for(int i=1;i<n;i++){
            if(heights[i]>=heights[s.top()]){
                s.push(i);
            }
            else{
                while(!s.empty()&&heights[i]<heights[s.top()]){
                    int mid=s.top();
                    s.pop();
                    if(!s.empty()){
                        int h=heights[mid];
                        int w=i-s.top()-1;
                        res=max(res,w*h);
                    }
                }
                s.push(i);
            }
        }


        return res;


    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值