4.20刷题记录(单调栈)

第一部分:简单介绍

单调栈我的理解是在栈中存储数字出现的位置,然后通过遍历比较当前栈顶元素与当前元素的大小关系,从而确定逻辑相关顺序。

第二部分:真题讲解

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

解题思路:在栈中存储每日的下标。如果当前元素大于栈顶元素,那么符合题意,就需要接下来的弹出以及赋值操作。如果小于等于则进行压栈。

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

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

解题思路:首先对数组2进行单调栈构建,然后将其存储到map中,避免两次遍历n^2的时间复杂度。然后通过map直接寻找即可。

cpp 复制代码
class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        vector<int>dict(nums2.size(),-1);
        vector<int>ans;
        stack<int>stack;

        for(int i=0;i<nums2.size();i++){
            while(stack.empty()==0&&nums2[i]>nums2[stack.top()]){
                int a=stack.top();
                stack.pop();
                dict[a]=nums2[i];
            }
            stack.push(i);
        }

        unordered_map<int,int>cnt;
        for(int i=0;i<nums2.size();i++){
            cnt[nums2[i]]=dict[i];
        }

        for(int i=0;i<nums1.size();i++){
            ans.push_back(cnt[nums1[i]]);
        }
        return ans;
    }
};

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

本题思路:与上一题类似,但是不同的是必须有一个循环。那么循环需要考虑模运算。这里只需要加一个入栈的条件即可,即stack.empty()||(i%n)!=stack.top()

cpp 复制代码
class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        //1.准备
        vector<int>dict(nums.size(),-1);
        stack<int>stack;
        int n=nums.size();

        //2.开始构建单调栈
        for(int i=0;i<nums.size()*2;i++){
            while(stack.empty()==0&&nums[i%n]>nums[stack.top()]){
                int a=stack.top();
                stack.pop();
                dict[a]=nums[i%n];
            }
            if(stack.empty()||(i%n)!=stack.top()){
                stack.push(i%n);
            }            
        }
        //3.output
        return dict;
    }
};

(4)42. 接雨水 - 力扣(LeetCode)

思路一:使用双指针法,按列相加,分别向左向右遍历,然后每一个位置的雨水=min(左,右)-height,然后累加就可以。

cpp 复制代码
class Solution {
public:
    int trap(vector<int>& height) {
        //1.initial
        vector<int>leftnum(height.size(),0);
        vector<int>rightnum(height.size(),0);
        int n=height.size();

        //2.look for
        leftnum[0]=height[0];
        for(int i=1;i<height.size();i++){
            leftnum[i]=max(leftnum[i-1],height[i]);
        }
        rightnum[n-1]=height[n-1];
        for(int i=n-2;i>=0;i--){
            rightnum[i]=max(rightnum[i+1],height[i]);
        }

        //3.sum
        int sum=0;
        for(int i=0;i<height.size();i++){
            sum+=min(leftnum[i],rightnum[i])-height[i];
        }
        return sum;
    }
};

思路二:单调栈(按行相加)

这个思路比较巧妙,如果成功构造了一个单调栈的话,那么就存在一种情况,b<a且b<c,其中b是栈顶元素,a是当前遍历到的数值,c是栈顶元素的下一个。那么就构成了接雨水的水槽。那么这个可以构成循环一直循环下去,所以我们只需要不断构建这个水槽就可以。

cpp 复制代码
class Solution {
public:
    int trap(vector<int>& height) {
        int n=height.size();
        vector<int>ans(n,0);
        stack<int>stack;
        int sum=0;
        //按行相加
        for(int i=0;i<n;i++){
            while(stack.empty()==0&&height[i]>height[stack.top()]){
                int a=stack.top();
                stack.pop();
                if(!stack.empty()){
                    int b=stack.top();
                    int alt=min(height[i],height[b])-height[a];
                    int width=i-b-1;
                    sum+=alt*width;
                }    
            }
            stack.push(i);
        }
        return sum;
    }
};

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

解题思路:

  1. 首先明确最大矩形怎么找:肯定是通过迭代一步一步更新来的。
  2. 那么怎么更新呢,就是通过先找到一个值,这个值右面的所有柱都比他大,也就是说直接用他的高去乘宽就是最大矩形。
  3. 如何用到单调栈呢,那就是说单调递减栈,如果当前元素比栈顶元素小则求矩形,否则(大于等于)则入栈。
  4. 还要在首尾加两个0,在尾节点加0是因为防止2468这种情况的存在。在头节点加是为了防止8642这种情况出现,无法进行计算,只是一味的弹出。
cpp 复制代码
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int>stack;
        int acre=0;
        //1.首先处理的时候要首尾加0
        heights.insert(heights.begin(),0);
        heights.push_back(0);

        //2.单调栈的构建
        for(int i=0;i<heights.size();i++){
            while(!stack.empty()&&heights[i]<heights[stack.top()]){
                //单调递减栈
                int mid=stack.top();
                stack.pop();
                if(!stack.empty()){
                    int left=stack.top();
                    int width=i-left-1;
                    int gaodu=heights[mid];
                    acre=max(acre,width*gaodu);
                }
            }
            stack.push(i);
        }

        //3.输出
        return acre;
    }
};
相关推荐
zru_96022 小时前
Java 中常用队列用法详解
java·开发语言
keep intensify3 小时前
杨氏矩阵、字符串旋转、交换奇偶位,offsetof宏
c语言·开发语言·数据结构·算法·矩阵
enyp803 小时前
c++ 类和动态内存分配
java·开发语言·c++
hy____1234 小时前
string类(详解)
开发语言·c++
跟着杰哥学Python4 小时前
一文读懂Python之numpy模块(34)
开发语言·python·numpy
氦客4 小时前
kotlin知识体系(六) : Flow核心概念与与操作符指南
android·开发语言·kotlin·协程·flow·冷流·热流
kk”4 小时前
二叉树的顺序结构及实现
c语言·数据结构
八了个戒5 小时前
「数据可视化 D3系列」入门第八章:动画效果详解(让图表动起来)
开发语言·前端·javascript·数据可视化
Villiam_AY5 小时前
go语言对http协议的支持
开发语言·http·golang