代码随想录算法训练营第42天|42. 接雨水、84.柱状图中最大的矩形

LeetCode42

2025-03-17 19:10:01 星期一

题目描述:力扣42
文档讲解:代码随想录(programmercarl)42. 接雨水
视频讲解:《代码随想录》算法视频公开课 (opens new window):单调栈,经典来袭!LeetCode:42.接雨水

代码随想录视频内容简记

这道题看着还挺唬人的,第六道困难。因为相比之前的题目多了一个部分就是需要同时求出一个元素左边和右边第一个比他大的元素,但是本质的东西没有变,还是求左右两边第一个比他大的元素和他之间的距离

梳理

  1. 初始化一个栈,同时初始化一个sum表示加和的结果

  2. 将0入栈

  3. 进行遍历,分三种情况进行比较

    1. 当前元素小于栈顶元素,入栈

    2. 当前元素等于栈顶元素,入栈。这里有个说法,就是如果先弹出栈顶元素,再将当前入栈和直接让当前入栈是没有区别的,因为在处理矩形的高的时候,是用左边矩形和右边矩形的高的最小值减去中间的值,所以即时不先弹出当前元素,他的面积也会是0

    3. 当前元素大于栈顶元素,此时对于栈顶元素来说,相当于找到了他右边第一个比他大的元素,也就是当前元素,还有左边第一个比他大的元素,也就他在栈中的下一个元素

  4. 接下来我们需要求凹槽的面积,首先求出高度,此时需要记录一下栈顶元素,int mid = height[st.top()],注意这里需要将其弹出,才能获取到这个栈顶元素左边第一个比他大的元素。同时,对左右两边的元素同时取min,也就是h = min(height[i], height[st.top()]) - mid;

  5. 之后求宽度,也就是w = i - st.top() - 1,这里需要多减1,看图中也可以看出,是4 - 2= 2,所以还需要进行- 1得到1。最后将所得到的元素进行累加即可

LeetCode测试

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

LeetCode84

题目描述:力扣84
文档讲解:代码随想录(programmercarl)84.柱状图中最大的矩形
视频讲解:《代码随想录》算法视频公开课:单调栈,又一次经典来袭! LeetCode:84.柱状图中最大的矩形

代码随想录视频内容简记

终于知道为什么k哥说这个和接雨水是遥相呼应了,因为这个是单调递减栈,我说感觉单调递增哪里不对,刚开始还试了一下双指针,属实是没想到。

梳理

  1. 初始化一个栈,初始化一个result = 0;

  2. 进行遍历,分三种情况

    1. 当前元素大于栈顶元素,入栈

    2. 当前元素等于栈顶元素,入栈。这里也能直接入栈,也能先弹出栈顶元素,再入栈。都不影响最后的结果,先入栈的话,计算出的面积会在后面的取max的部分被覆盖掉,所以没有关系

    3. 当前元素小于栈顶元素,首先用mid记录栈顶元素,pop()之后,进入while循环,这里就是收获结果的地方了。此时的栈顶元素是mid左边第一个比他小的元素,用left记录,而当前元素是mid右边第一个比他小的元素,用right记录。同样,矩形的高就是heights[mid],矩形的宽就是right - left - 1。这样就得到了矩形的面积,记录最大值即可。

这里注意,不是在图中红框的位置进行面积的计算

而是找到每一个比中间元素高的矩形进行计算

  1. 对原数组进行处理,这里是很重要的一步。这里特殊的地方就是需要进行在原数组头部和尾部进行插入0,这里k哥举了两个例子,一个是[8,6,4,2],原数组递减,那么在遍历的时候会触发第三种情况,但是每次在栈中的元素只有两个,弹出一个就是个空栈了,所以操作进行不下去;另外一个是[2,4,6,8],原数组递增,那么在遍历的时候全都入栈,压根没有触发第三种情况,那么就也不会有操作。

LeetCode测试

第七道困难

点击查看代码
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        stack<int> st;
        st.push(0);
        int result = 0;
        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.push(i);
            else {
                while (!st.empty() && heights[i] < heights[st.top()]) {
                    int mid = heights[st.top()];
                    st.pop();
                    if (!st.empty()) {
                        int h = mid;
                        int left = st.top();
                        int right = i;
                        int w = right - left - 1;
                        result = max(result, h * w);
                    }
                }
                st.push(i);
            }
        }
        return result;
    }
};
posted on 2025-03-17 19:10  bnbncch  阅读(15)  评论(0)    收藏  举报