代码随想录算法训练营day44

0 阅读5分钟

739.每日温度 单调栈的设计思路:通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为O(n)。

理解结果数据不一定要一定按照顺序录入之后,很多问题就迎刃而解了

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        //使用单调栈在O(n)时间复杂度内解决问题
        //设计单调栈
        stack<int> st;
        //设计存储结果的返回数组
        vector<int> result(temperatures.size(),0);
        //初始化,先将数组下标0入栈
        st.push(0);
        //执行迭代递推逻辑
        for(int i=1;i<temperatures.size();i++){
            if(temperatures[i]<temperatures[st.top()]){//不满足条件,遍历温度比栈顶温度低
                //执行入栈
                st.push(i);
            }
            else if(temperatures[i]==temperatures[st.top()]){//不满足条件,遍历温度和栈顶温度相等
                //执行入栈
                st.push(i);
            }
            else {//满足条件开始录入结果
                while(!st.empty() && temperatures[i] > temperatures[st.top()]){//注意这里要防止空栈问题
                    //录入结果
                    result[st.top()]=i-st.top();
                    st.pop();
                }
               //将遍历的新结果入栈
                st.push(i);
            }
        }
        return result;
        
    }
};

496.下一个更大元素 难点解析:这道题远比上一道单调栈绕,需要综合运用hash表,单调栈等知识点 1.使用hash表快速查找nums1的数据内容和下标, 2.明确单调栈的入栈对象是nums2的下标 3.result初始化的对象是nums1的结果,应当全部初始化为-1; 4.明确栈顶元素比较的对象!!! 5.正确设计匹配情况应该怎么存入结果,这部分类似上题。

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        //使用单调栈解答问题
        //首先设计单调栈
        stack<int> st;
        //使用result存储结果
        vector<int> result(nums1.size(),-1);
        //剪支排除意外情况
        if(nums1.size()>nums2.size())
        return result;
        //对nums1进行预处理,方便快速查找下标或结果
        unordered_map<int,int> countmap;
        for(int i=0;i<nums1.size();i++){
            countmap[nums1[i]]=i;
        }
        //初始化单调栈,将下标0入栈
        st.push(0);
        //开始执行迭代关系,递推方程
        for(int i=1;i<nums2.size();i++){
            //根据不同情况判断
            //小于等于情况,入栈
            if(nums2[i]<=nums2[st.top()]){
               st.push(i);
            }
            else {//大于情况
               while(!st.empty()&& nums2[i] > nums2[st.top()]){//注意防止空栈情况
                  if(countmap.count(nums2[st.top()])>0){//确定是否存在这个元素在hash表中
                      int index=countmap[nums2[st.top()]];
                      result[index]=nums2[i];//把满足条件的元素存入结果中
                  }
                  st.pop();
               }
               st.push(i);
            }
        }
        return result;
    }
};

503.下一个更大元素 变成循环数组之后,要学会使用取余来进行运算

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        //使用单调栈
        vector<int> result(nums.size(),-1);//在同等规模情况下全部初始化为-1;
        //剪支处理
        if(nums.size()==0) return result;
        //设计单调栈
        stack<int> st;
        //初始化
        st.push(0);
        //考虑到为循环数组,可以使用衔接,也可以使用除余达成双倍循环目的
        for(int i=1;i<2*nums.size();i++){//注意,这里是从1开始遍历,因为0已经入栈了
            if(nums[i%nums.size()]<=nums[st.top()]){//将新下标入栈,注意,这里是通过取余来进行取数
              st.push(i%nums.size());//入栈的是下标
            }
            else{//满足条件情况
                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; 
    }
};

42.接雨水问题 1.采用双指针方式是从列的方式进行计算 2.采用单调栈的方式是从行的方式进行计算,如何设计核心单调出栈逻辑还是需要画图来处理

class Solution {
public:
    int trap(vector<int>& height) {
        //类似求下一个较大元素之差
        //采用单调栈的做法
        //使用result存储所有结果
        int result=0;
        //设计单调栈
        stack<int> st;
        //入栈初始化
        st.push(0);
        //执行单调迭代,并且需要注意,必须满足height[i]<height[j]且雨水量为j-i-1;设置mid,通过height[i],st.top()三个元素来计算雨水体积
        for(int i=1;i<height.size();i++){//注意边界从1开始
            if(height[i]<height[st.top()]){//出现小于栈顶元素的情况,入栈
                st.push(i);//存储下标
            }
            else if(height[i]==height[st.top()]){//出现相同情况,把之前的栈顶元素出栈,然后执行入栈操作
                st.pop();
                st.push(i);//存储下标
            }
            else{
                while(!st.empty()&&height[i]>height[st.top()]){
                    //设置mid作为中间凹点
                    int mid=st.top();
                    st.pop();
                    // 关键修正2:弹出mid后先判断栈是否为空(避免空栈访问)
                    if (st.empty()) break;
                    int left=st.top();
                    int right=i;
                    //计算雨水体积
                    int h=min(height[left],height[right])-height[mid];//求高
                    int l=right-left-1;//求宽
                    int m=h*l;
                    result=m+result;
                }
                st.push(i);//存储下标
            }
        }
        return result;
    }
};

84柱状图最大面积 弄明白矩形怎么算,不仅要考虑入栈的满足条件的情况,还要考虑不满足条件时,也就是所有元素都入栈却没有相应条件的情况!!! 这些怎么算具体看代码!!!

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        //类似雨水问题,雨水问题是求当前柱左右两次大于其的第一个的柱子高度,这里最大矩形是求当前柱左右两侧第一个小于其的柱子高度
        //剪支排除意外情况
        if(heights.size()==0) return 0;
        //设计单调栈,栈内存储的是heights的下标
        stack<int> st;
        //初始化st,将下标0入栈
        st.push(0);
        int result=0;//初始化result=0;
        //遍历heights并分情况进行对比
        for(int i=1;i<heights.size();i++){
            if(heights[i]>heights[st.top()]){//情况一,高度大于栈顶下标元素的高度,当前遍历下标入栈
                st.push(i);
            }
            else if(heights[i]==heights[st.top()]){//情况二,当前遍历高度等于栈顶下标元素的高度,
                st.pop();
                st.push(i);
            }
            else{
                while(!st.empty()&&heights[i]<heights[st.top()]){
                    int mid=st.top();
                    st.pop();
                // 关键修正:栈空时宽度为i,而非直接break
                    int h = heights[mid];
                    int w = 0;
                    if (st.empty()) {
                        w = i; // 左边界不存在,宽度为当前i(左侧所有位置都可作为矩形宽度)
                    } else {
                        int left = st.top();
                        w = i - left - 1; // 左边界存在,宽度=右-左-1
                    }
                    result = max(h * w, result);
                }
                st.push(i);
            }
            
        }
        // 关键修正2:处理栈中剩余元素(右侧无更小值,右边界为heights.size())
        while (!st.empty()) {
            int mid = st.top();
            st.pop();
            int h = heights[mid];
            // 右边界为数组长度,左边界逻辑同上
            int w = st.empty() ? heights.size() : (heights.size() - st.top() - 1);
            result = max(h * w, result);
        }
        return result;
    }
};