day58 单调栈

这篇具有很好参考价值的文章主要介绍了day58 单调栈。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

单调栈

使用场景:通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置

本质:空间换时间

三个判断条件
当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况

739. 每日温度

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        stack<int>s;
        vector<int>result(temperatures.size(), 0);
        s.push(0);
        int index = 1;
        while(index < temperatures.size()){
            while(!s.empty() && temperatures[s.top()] < temperatures[index]){
                int temp = s.top();
                s.pop();
                result[temp] = index - temp;
            }
            s.push(index);
            index++;
        }
        return result;
    }
};

496. 下一个更大元素 I
题目: 给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。

思路 : num2作单调栈找下一个大的值,弹出时,判断是否在num1中出现过,如果出现则进行赋值,链接使用unordered_map

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        vector<int>result(nums1.size(), -1);
        unordered_map<int, int>m;
        stack<int>s;
        for(int i=0; i<nums1.size();i++){
            m[nums1[i]] = i;  
        }
        s.push(0);
        int index = 1;
        while(index < nums2.size()){
            while(!s.empty() && nums2[s.top()] < nums2[index]){ //弹出时判断
                if(m.find(nums2[s.top()]) != m.end()){
                    result[m[nums2[s.top()]]] = nums2[index];
                }
                s.pop();
            }
            s.push(index);
            index++;
        }
        return result;
    }
};

503. 下一个更大元素 II

题目:循环数组

简单版: 两个数组拼接在一起,然后使用单调栈求下一个最大值

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

改进版: 不扩充nums,而是在遍历的过程中模拟走了两边nums

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

42. 接雨水

day58 单调栈,算法

  1. 暴力
    思路:如果按照列来计算的话,宽度一定是1了,我们再把每一列的雨水的高度求出来就可以了
    每一列雨水的高度,取决于,该列左侧最高的柱子和右侧最高的柱子中最矮的那个柱子的高度。

问题:复杂度为O(n^2) 超时

class Solution {
public:
    int trap(vector<int>& height) {
        int sum = 0;
        for(int i=1; i<height.size()-1; i++){
            int left = 0;
            int right = 0;
            for(int j=i; j>=0; j--){
                left = max(left, height[j]);
            }
            for(int j=i; j<height.size(); j++){
                right = max(right, height[j]);
            }
            sum += min(left, right) - height[i];
        }
        return sum;
        
    }
};

2.双指针改进暴力 空间换时间 提前将左右最高高度算出来

class Solution {
public:
    int trap(vector<int>& height) {
        int sum = 0;
        vector<int>left(height.size(), 0);
        vector<int>right(height.size(), 0);
        int m_left = height[0];
        int m_right = height[height.size()-1];
        
        for(int i=0; i<height.size(); i++){
            m_left = max(m_left, height[i]);
            left[i] = m_left;
        }

        for(int i=height.size()-1; i>=0; i--){
            m_right = max(m_right, height[i]);
            right[i] = m_right;
            
        }

        for(int i=1; i<height.size()-1; i++){
            sum += min(left[i], right[i]) - height[i];
        }
        return sum;
        
    }
};
  1. 双指针
    day58 单调栈,算法
    思路:
    单调栈是按照行方向来计算雨水
    栈顶和栈顶的下一个元素以及要入栈的元素,三个元素来接水
    雨水高度是 min(凹槽左边高度, 凹槽右边高度) - 凹槽底部高度
    水的宽度是 凹槽右边的下标 - 凹槽左边的下标 - 1
class Solution {
public:
    int trap(vector<int>& height) {
        stack<int>s;
        int sum = 0;
        s.push(0);
        for(int i=1; i<height.size(); i++){
            while(!s.empty() && height[s.top()] < height[i]){          
                int cur = s.top();
                s.pop();
                if(!s.empty()){  //来避免 栈内[2] 元素3 村水量 0 只要弹出就可以了
                    int h =  min(height[i], height[s.top()]) - height[cur]; 
                    sum += h * (i-s.top()-1);
                }

            }
             s.push(i); 
        }
        return sum;
    }
};

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

求在该柱状图中,能够勾勒出来的矩形的最大面积。
day58 单调栈,算法
主体思路:
每一个位置能达到的最大面积取决于它左右两侧小于它的高度位置。
int w = right-left - 1;
int h = heights[i];
sum = max(sum, w*h);

暴力超时

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int sum = 0;
        for(int i=0; i<heights.size(); i++){
            int left = i;
            int right = i;
            while(left >= 0){
                if(heights[left] < heights[i]) break;
                left--;
            }
            while(right < heights.size()){
                if(heights[right] < heights[i]) break;
                right++;
            }
            int w = right-left - 1;
            int h = heights[i];
            sum = max(sum, w*h);
        }
        return sum;
    }
};

双指针优化,空间换时间,提前记录左右两侧的位置信息没有数组保存时,需要一个一个跳进行比较。有数组后,那么可以利用之前的比较信息进行跳着比较。
heights[left] >= heights[i]) 时
直接跳到 left[left]指向的位置
注意
left是往左跳 则遍历顺序从左到右
right 向右跳,则右边的先算,遍历顺序从右向左

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        vector<int>left(n, -1);
        vector<int>right(n, n);

        for(int i=0; i<n; i++){
            int l = i-1;
            while(l>=0 && (heights[l] >= heights[i])) l = left[l];
            left[i] = l; 
          
        }
        for(int i=n-1; i>=0; i--){
            int r = i+1;
            while(r < n && (heights[r] >= heights[i])) r = right[r];
            right[i] =r;
        }

        int sum=0; 
        for(int i=0; i<n; i++){
        sum = max(sum, heights[i] *(right[i]-left[i]-1));
           
        }
        return sum;

    }
};

单调栈:目的找到左右两侧第一个比它小的元素
栈内元素从小到大,
day58 单调栈,算法
当前元素小于栈顶元素时, 当前元素就是右边界,栈顶元素的下一个元素就是左边界, w = right - left - 1 h = height[s.top()] sum = max(sum, h*w)
注意两种情况文章来源地址https://www.toymoban.com/news/detail-620937.html

  1. 2 3 4 5 递增序列没有机会弹出 所以在最后面加入一个0 —> 2 3 4 5 0
  2. 8 7 6 5 第一个元素没有左边界 所以在最前面加入一个0 —> 0 8 7 6 5
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
       
        heights.push_back(0);
        heights.insert(heights.begin(), 0);
        int n = heights.size();
        stack<int>s;
        s.push(0);
        int sum = 0;
        for(int i=1; i<n; i++){
            if(heights[i] > heights[s.top()]){
                   s.push(i);
            }else if(heights[i] == heights[s.top()]){
                s.pop();
                s.push(i);
            }else{
                while(!s.empty() && (heights[i] < heights[s.top()])){
                       int mid = s.top();
                       s.pop();
                       if(!s.empty()){
                           int left = s.top();
                           int w = i-left-1;
                           int h = heights[mid];
                           sum = max(sum, w*h);
                       }
                      
                   }
                   s.push(i);
               }
           
        }
        return sum;
    }
};

到了这里,关于day58 单调栈的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 力扣算法刷题Day59|单调栈

    力扣题目:# 503.下一个更大元素II  刷题时长:参考题解后2min 解题方法:单调栈 复杂度分析 时间O(n) 空间O(n) 问题总结 如何解决环的问题 本题收获 循环数组解决方案 思路一:将两个nums数组拼接在一起,使用单调栈计算出每一个元素的下一个最大值,最后再把结果集即res

    2024年02月13日
    浏览(46)
  • DAY40:贪心算法(九)单调递增的数字(贪心的思路)

    本题暴力解法也需要看一下,虽然暴力解法超时了,但是这种思路是一种很基础的思路,需要了解 数字是没有办法直接采用下标遍历的 ,如果 要for循环遍历每个位置的数字,需要把数字转成字符串string 当且仅当每个相邻位数上的数字 x 和 y 满足 x = y 时,我们称这个整数是

    2024年02月12日
    浏览(37)
  • 算法训练day37|贪心算法 part06(LeetCode738.单调递增的数字)

    题目链接🔥🔥 给定一个非负整数 N,找出小于或等于 N 的最大的整数,同时这个整数需要满足其各个位数上的数字是单调递增。 (当且仅当每个相邻位数上的数字 x 和 y 满足 x = y 时,我们称这个整数是单调递增的。) 示例 1: 输入: N = 10 输出: 9 示例 2: 输入: N = 1234 输出:

    2024年02月09日
    浏览(28)
  • 算法刷题Day 37 单调递增的数字+监听二叉树

    两个可能经常要用到的函数 字符串转数字: to_string() 数字转字符串: stoi() 利用树后续遍历,同时加上状态转移的方法,非常值得反复学习

    2024年02月13日
    浏览(26)
  • 算法打卡day32|贪心算法篇06|Leetcode 738.单调递增的数字、968.监控二叉树

    Leetcode 738.单调递增的数字 题目链接:738.单调递增的数字  大佬视频讲解:单调递增的数字视频讲解  个人思路 这个题目就是从例子中找规律,例如 332,从后往前遍历,32不是单调递增将2变为9,3减1,变成了329,遍历到2,32不是递增,将2变为9,3减1,变成299,符合题目条件,打印

    2024年04月16日
    浏览(31)
  • Day37 贪心算法 part06 738. 单调递增的数字 968. 监控二叉树

    建议二刷巩固

    2024年01月23日
    浏览(30)
  • 【LeetCode题目详解】第八章 贪心算法 part06 738.单调递增的数字 968.监控二叉树 (day37补)

    当且仅当每个相邻位数上的数字  x  和  y  满足  x = y  时,我们称这个整数是 单调递增 的。 给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。 示例 1: 示例 2: 示例 3: 提示: 0 = n = 109 # 暴力解法 题意很简单,那么首先想的就是暴力解法了,来我替大家

    2024年02月10日
    浏览(32)
  • day58_LayUI

    layui(谐音:类 UI) 是一套开源的Web UI解决方案,采用自身经典的 模块化 规范,并遵循原生HTML/CSS/JS的开发方式, 常适合网页界面的快速开发 。layui 区别于那些基于MVVM 底层的前端框架,它更多是 面向后端开发者 ,无需涉足前端各种工具,只需面对浏览器本身,让一切所需

    2024年02月11日
    浏览(27)
  • day58

     739. 每日温度   496.下一个更大元素 I    739. 每日温度  今天正式开始单调栈,这是单调栈一篇扫盲题目,也是经典题。 大家可以读题,思考暴力的解法,然后在看单调栈的解法。 就能感受出单调栈的巧妙 代码随想录  496.下一个更大元素 I  本题和 739. 每日温度 看

    2024年02月10日
    浏览(32)
  • 代码随想录Day58

    昨天因为志愿活动和笔试耽误了一整天,今天继续学习动规解决子序列问题。 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,\\\"ace\\\"是\\\"abcde\\\"的一个子序列,

    2023年04月27日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包