代码随想录算法训练营第四十九天|单调栈part2

发布于:2025-07-15 ⋅ 阅读:(20) ⋅ 点赞:(0)

42. 接雨水

题目链接:42. 接雨水 - 力扣(LeetCode)

文章讲解:代码随想录

思路:

height = [4,2,0,3,2,5]为例

先求每根柱子左右边第一个高的

得到

5 3 3 5 5 -1

-1 4 2 4 3 -1

左右两边都不为-1才能接住水

初始化ans 为0

左右两边都不为-1的置为1

对于1 里边都能盛水

所盛水是 1的左右两边柱子的最小值 然后再减去1的柱子里边原本的高度

然后统计所有的水 j

class Solution {
public:
    int trap(vector<int>& height) {
        vector<int>right(height.size(),-1);
        vector<int>left(height.size(),-1);
        stack<int>st;
        st.push(0);
        for(int i=1;i<height.size();i++){   //右边第一个大的
            while(!st.empty()&&height[i]>height[st.top()]){
                right[st.top()]=height[i];
                st.pop();
            }
            st.push(i);
        }
        stack<int>lst;
        lst.push(height.size()-1);
        for(int i=height.size()-2;i>=0;i--){   //左边第一个大
            while(!lst.empty()&&height[i]>height[lst.top()]){
                left[lst.top()]=height[i];
                lst.pop();
            }
            lst.push(i);
        }
        vector<int>ans(height.size(),1);

        for(int i=0;i<height.size();i++){  //能盛水的单位
            if(left[i]==-1||right[i]==-1){
                ans[i]=0;
            }
        }
        for(int i=0;i<height.size();i++){
            if(ans[i]){
                int l=i-1;              //能盛水的区间
                int r;
                for(int j=i;j<height.size();j++){
                    if(ans[j]==0){
                        r=j;
                        break;
                    }
                }
                int num=min(height[l],height[r]);
                for(int j=l+1;j<r;j++){    //能盛水的区间每个柱子能接的水
                    ans[j]=num-height[j];
                }
                i=r-1;
            }
        }
        int result=0;
        for(auto &x:ans){
            result+=x;
        }
       return result; 
    }
};

解法2:

暴力解:

需要优化

class Solution {
public:
    int trap(vector<int>& height) {
        //暴力解法 求每根柱子能盛的水
        vector<int>lmax(height.size(),0);
        vector<int>rmax(height.size(),0);
        vector<int>ans(height.size(),0);
        int n=height.size();
        // 计算每个柱子左边最高的柱子
        for (int i = 1; i < n; ++i) {
            lmax[i] = max(lmax[i - 1], height[i - 1]);
        }

        // 计算每个柱子右边最高的柱子
        for (int i = n - 2; i >= 0; --i) {
            rmax[i] = max(rmax[i + 1], height[i + 1]);
        }
       for(int i=1;i<height.size()-1;i++){
        ans[i]=min(lmax[i],rmax[i])-height[i];
       }

        int result=0;
        for(auto &x:ans){
            if(x>=0) result+=x;
        }
       return result; 
    }
};

 方法三:

单调栈

class Solution {
public:
    int trap(vector<int>& height) {
        int result=0;
        stack<int>st;
        st.push(0);
        for(int i=1;i<height.size();i++){
            if(!st.empty()&&height[i]<height[st.top()]){
                st.push(i);
            }else if(!st.empty()&&height[i]==height[st.top()]){
                st.push(i);
            }else{
                while(!st.empty()&&height[i]>height[st.top()]){
                    int mid=st.top();
                    st.pop();
                    if (st.empty()) break;  // ✅ 必须加这个判断
                    int h=min(height[st.top()],height[i]);
                    int w=i-st.top()-1;//水量计算
                    result+=w*(h-height[mid]);    
                }
                st.push(i);   //这一句放在循环外
            }
        }
       return result; 
    }
};
84.柱状图中最大的矩形

 思路:

考虑每个柱子的高度为高,然后计算最大的宽度,再计算面积。

比较上述面积的最大值

宽度的计算在于 寻找当前柱子左右两边第一个比它小的 l和r

那么w=r-l-1

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int size=heights.size();
        vector<int>leftMin(heights.size(),-1);   //左边第一个小的
        vector<int>rightMin(heights.size(),size); //右边第一个小的
        stack<int>lst;
        stack<int>rst;
        rst.push(0);
        for(int i=1;i<size;i++){
            while(!rst.empty()&&heights[i]<heights[rst.top()]){
                rightMin[rst.top()]=i;
                rst.pop();
            }
            rst.push(i);
        }
        lst.push(size-1);
        for(int i=size-2;i>=0;i--){
            while(!lst.empty()&&heights[i]<heights[lst.top()]){
                leftMin[lst.top()]=i;
                lst.pop();
            }
            lst.push(i);
        }
        int result=0;
        for(int i=0;i<size;i++){
            int r=rightMin[i];
            int l=leftMin[i];
            int w=r-l-1;
            int area=w*heights[i];
            result=max(result,area);
        }
        return result;
        
    }
};


网站公告

今日签到

点亮在社区的每一天
去签到