代码随想录-笔记-其十

今天写个短的笔记来专门记录一下有关代码随想录中单调栈的题目:

单调栈的作用其实非常的简单易懂:他就是用来寻找每个数组内元素往右第一个比他大的元素。(或者小的,或者往左,方向和大小不卡死)如果单调栈是递增的,那么求的就是比他大的元素,我们这样想更直观:加入的元素比栈顶的元素大的话,说明我们找到了比之前遍历的元素更大的元素了,反之亦然。

739. 每日温度 - 力扣(LeetCode)

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。

cpp 复制代码
class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        vector<int> res(temperatures.size());
        stack<int> stk;
        for(int i=0;i<temperatures.size();++i){
            while(!stk.empty()&&temperatures[i]>temperatures[stk.top()]){
                int pre=stk.top();
                stk.pop();
                res[pre]=i-pre;
            }
            stk.push(i);
        }
        return res;
    }
};

一个很简单的单调栈的题目,我们用栈来记录已经遍历过的序号并且向右寻找第一个比当前元素更大的元素,得到之后就将结果放在res数组里。

496. 下一个更大元素 I - 力扣(LeetCode)

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

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

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

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

cpp 复制代码
class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        vector<int> res;
        stack<int> stk;
        unordered_map<int,int> mp;
        for(int num:nums2){
            while(!stk.empty()&&num>stk.top()){
                mp[stk.top()]=num;
                stk.pop();
            }
            stk.push(num);
        }
        for(int& num:nums1){
            num=mp.count(num)?mp[num]:-1;
        }
        return nums1;
    }
};

这个题比起上一个题来说要绕得多,但是我们可以利用哈希表的性质(count,contains等)来先在nums2中执行找到右边第一个比当前大的值,然后反过来去nums1寻找重复的值。

503. 下一个更大元素 II - 力扣(LeetCode)

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

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

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

所谓的循环数组只需要我们去寻找两遍即可,我们主要需要做的是注意序号的取余操作。

42. 接雨水 - 力扣(LeetCode)

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

cpp 复制代码
class Solution {
public:
    int trap(vector<int>& height) {
        int res=0,left=0,right=height.size()-1;
        int leftmax=height[0],rightmax=height.back();
        while(left<right){
            if(height[left]<height[right]){
                res+=leftmax-height[left];
                left++;
                leftmax=max(leftmax,height[left]);
            }
            else{
                res+=rightmax-height[right];
                right--;
                rightmax=max(rightmax,height[right]);
            }
        }
        return res;
    }
};

这是双指针做法,我们维护左右指针以及左右最大值,慢慢推进左右指针并将每一步移动的值相加即可。

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

这个是单调栈做法,其实本质上也是寻找向右的第一个比当前值大的值,这里巧妙的利用了单调栈的另一个性质:栈顶元素的栈内下一个元素一定也是比当前大的,也就是也是当前元素向左的第一个比当前值大的元素(如果不是的话就会触发while的条件,被弹出栈外),所以我们可以同时得到当前元素向左和向右的第一个比当前元素大的元素,我们就将结果相加即可。

84. 柱状图中最大的矩形 - 力扣(LeetCode)

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

cpp 复制代码
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int res=0;
        heights.insert(heights.begin(),0);
        heights.push_back(0);
        stack<int> stk;
        stk.push(0);
        for(int i=1;i<heights.size();++i){
            while(heights[stk.top()]>heights[i]){
                int mid=stk.top();
                stk.pop();
                int h=heights[mid];
                int w=i-stk.top()-1;
                res=max(res,h*w);
            }
            stk.push(i);
        }
        return res;
    }
};

这个题需要注意的点是我们的边界初始化:我们这题需求的是找寻当前值两遍的第一个比当前值小的值,那如果我们从局部最小值开始可能会出现完全不触发while的条件,于是为了保证至少进行一次面积的计算,我们在最后和最开始的数组处都添加一个0,而stack处添加0则是为了对应一开始添加的0序号上的对应(不然会对不上序号)。

单调栈的题都有着比较明显的用意:找寻每个元素的往左、往右的第一个比当前值大、小的值,而且思路总的来说比较模板,还是比较简单的。

相关推荐
细心的莽夫12 分钟前
Spring 复习笔记
java·笔记·学习·spring·java-ee
颖风船34 分钟前
(初学者)STM32 MP157中LED触发器笔记
笔记·stm32·嵌入式硬件
魔理沙偷走了BUG39 分钟前
【数学建模笔记】评价模型-基于熵权法的TOPSIS模型
笔记·数学建模
挥剑决浮云 -1 小时前
STM32学习之 模块初始化和常用GPIO函数笔记
笔记·stm32·学习
笑鸿的学习笔记1 小时前
qt-C++笔记之动画框架(Qt Animation Framework)入门
c++·笔记·qt
Octopus20772 小时前
链地址法(哈希桶)
c++·笔记·学习·算法·哈希算法
GISDance2 小时前
26考研资料分享 百度网盘
经验分享·笔记·考研·百度
灰原A3 小时前
【Unity笔记】如何把语言修改为简体中文?
笔记
Jackilina_Stone3 小时前
【HUAWEI】HCIP-AI-MindSpore Developer V1.0 | 第四章 图像处理原理与应用(2 图像预处理技术) | 学习笔记
图像处理·人工智能·笔记·学习·计算机视觉·huawei
Jackilina_Stone5 小时前
【HUAWEI】HCIP-AI-MindSpore Developer V1.0 | 第四章 图像处理原理与应用(1 图像处理概览) | 学习笔记
人工智能·笔记·计算机视觉·huawei