接雨水

原始思路

形成凹槽的条件是value[l]<value[i]<value[r],能接到的雨水是比较大的值矩形减去这之间的值和。

暴力解法

思路:通过左边的最高柱子和右边的最高柱子的小值确定当前位置可承接的雨水。

class Solution {
public:
    int trap(vector<int>& height) {
        int sum = 0;
        for (int i = 0; i < height.size(); i++) {
            if (i == 0 || i == height.size() - 1)
                continue;

            int rheight = height[i];
            int lheight = height[i];
            for (int r = i + 1; r < height.size(); r++) {
                if (height[r] > rheight)
                    rheight = height[r];
            }
            for (int l = i - 1; l >= 0; l--) {
                if (lheight < height[l])
                    lheight = height[l];
            }
            sum += min(lheight, rheight) - height[i];
        }
        return sum;
    }
};

优化双指针解法

设置一个等大的数组用来存放左大值和右大值,如此就不需要每次对所有的左值和右值进行遍历,仅需比较当前值与上一个左值或者右值的大小。需要注意右值是从末端开始确定,初始化为height[height.size()-1],从height.size()-2 开始遍历;

具体实现

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

单调栈解法

整体上并不难理解,依靠当遍历到的元素大于栈头元素时,弹出栈头元素,此时,新的栈头,弹出元素和当前元素形成了凹槽。其高度为当前元素与栈头元素中较小的一个与槽底元素(弹出元素)之差,宽度为当前元素与栈头中间的距离:w = i - st.top() - 1

class Solution {
public:
    int trap(vector<int>& height) {
        int sum = 0;
        stack<int> st;
        st.push(0);
        for (int i = 1; i < height.size(); i++) {
            while (!st.empty() && height[i] > height[st.top()]) {
                int popped = st.top();
                st.pop();
                if (!st.empty()) {
                    int h = min(height[i], height[st.top()]) - height[popped];
                    int w = i - st.top() - 1;
                    sum += h * w;
                }
            }
            st.push(i);
        }
        return sum;
    }
};

柱状图中最大的矩形

解法思路

使用一个递减的单调栈,小的话,说明前面的已经不能用了。边界时注意在头尾增加0,对递增数组或者只有一个元素没有收集结果过程进行预防。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int> st;   
        int result=0;
        heights.insert(heights.begin(),0);
        heights.push_back(0);
        st.push(0);
        for(int i=1;i<heights.size();i++){
            while(!st.empty()&&heights[i]<heights[st.top()]){
                int poppped=st.top();
                st.pop();
                int h=heights[poppped];
                int w=i-st.top()-1;
                result=max(h*w,result);
            }
            st.push(i);
        }
        return result;
    }
};

时间复杂度:O(n)

posted on 2025-12-24 16:13  FAfa_C++  阅读(2)  评论(0)    收藏  举报