算法 DAY59 单调栈2 503.下一个更大元素II 42. 接雨水 84.柱状图中最大的矩形

503.下一个更大元素II

难点在于如何是实现数组的循环
算法 DAY59 单调栈2 503.下一个更大元素II 42. 接雨水 84.柱状图中最大的矩形_第1张图片但使用模拟遍历两次的时候注意始终使用index,别出现越界

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

42. 接雨水

本题首先要明确:按行统计还是按照列统计。
核心思想:按列统计,找到每一列左右两侧的最大值,取其中最小值,减去当前值就是这一列的雨水。其中第一根柱子和最后一根不做统计。
例如求列4的雨水高度:
算法 DAY59 单调栈2 503.下一个更大元素II 42. 接雨水 84.柱状图中最大的矩形_第2张图片列4 = min(2 , 3) - 1 = 1

1、暴力解法

那么暴力解法就是遍历数组,同时嵌套for寻找两边的最大值,这样时间复杂度就是O(n2),超时

2、双指针优化
但其实没必要嵌套for数组,直接用数组遍历两边,每个列左边最大值记录在maxLeft数组,右边记录在maxRight数组就行。最后再遍历原始数组。

class Solution {
public:
    int trap(vector<int>& height) {
        vector<int> maxLeft(height.size(),0);
        vector<int> maxRight(height.size(),0);
        maxLeft[0] = height[0];
        for(int i = 1; i < height.size();++i){
            maxLeft[i] = max(height[i],maxLeft[i-1]);
        }
        maxRight[height.size()-1] = height[height.size()-1];
        for(int i = height.size()-2;i>=0;i--){
            maxRight[i] = max(maxRight[i+1],height[i]);
        }

        int sum = 0;
        for(int i = 1;i<height.size()-1;++i){
            int temp = min(maxLeft[i-1],maxRight[i+1]) - height[i];
            if(temp>0) sum+= temp;
        }
        return sum;
    }
};

3、单调栈解法
单调栈是按照行方向来计算雨水
算法 DAY59 单调栈2 503.下一个更大元素II 42. 接雨水 84.柱状图中最大的矩形_第3张图片
一旦发现添加的柱子高度大于栈头元素了,此时就出现凹槽了,栈头元素就是凹槽底部的柱子,栈头第二个元素就是凹槽左边的柱子,而添加的元素就是凹槽右边的柱子。
算法 DAY59 单调栈2 503.下一个更大元素II 42. 接雨水 84.柱状图中最大的矩形_第4张图片
算法 DAY59 单调栈2 503.下一个更大元素II 42. 接雨水 84.柱状图中最大的矩形_第5张图片

情况一:当前遍历的元素(柱子)高度小于栈顶元素的高度 height[i] < height[st.top()] 直接push
情况二:当前遍历的元素(柱子)高度等于栈顶元素的高度 height[i] == height[st.top()] 替换下标
情况三:当前遍历的元素(柱子)高度大于栈顶元素的高度 height[i] > height[st.top()] 利用左中右三个元素来求雨水

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){
            while(!st.empty() && height[i] > height[st.top()]){
                int mid = st.top();
                st.pop();
                if(!st.empty()){
                    int h = min(height[st.top()],height[i])-height[mid];
                    int w = i-st.top()-1;
                    sum += h*w;
                }
            }
            st.push(i);
        }
        return sum;
    }
};

84.柱状图中最大的矩形

跟接雨水相似,但是又不同。42. 接雨水 (opens new window)是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子的柱子。
算法 DAY59 单调栈2 503.下一个更大元素II 42. 接雨水 84.柱状图中最大的矩形_第6张图片只有栈里从大到小的顺序,才能保证栈顶元素找到左右两边第一个小于栈顶元素的柱子。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int> st;
        heights.insert(heights.begin(), 0); // 数组头部加入元素0
        heights.push_back(0); // 数组尾部加入元素0
        st.push(0);
        int result = 0;
        for (int i = 1; i < heights.size(); i++) {
            while (heights[i] < heights[st.top()]) {
                int mid = st.top();
                st.pop();
                int w = i - st.top() - 1;
                int h = heights[mid];
                result = max(result, w * h);
            }
            st.push(i);
        }
        return result;
    }
};

你可能感兴趣的:(算法,数据结构,leetcode)