代码随想录第62天 | 503.下一个更大元素II 、 42. 接雨水

一、前言

参考文献:代码随想录

今天的主题还是单调栈,主要思考方式判断怎么利用这个栈,来实现记录数据的问题;

二、下一个更大元素||

1、思路:

这个题目和昨天的温度问题如出一辙,只是多了一个回环数组而已,仅此而已,所以就可以扩充数组,或者遍历两遍;

单调栈在这里的作用还是做一个单调递增的单调栈,来存储下一个最大数字的下标;

2、整体代码如下:

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

三、接雨水

1、思路:

(1)我一开始的双指针思路如下:

int trap(vector<int>& height) {
    int n = height.size();
    if (n < 3) return 0;
    int left;
    for (int i = 0; i < n; i++) {
        if (height[i] != 0) {
            left = i;
            break;
        }
    }
    int right = left + 1;
    int maxRain = 0;
    int sum = 0;
    while (left < n) {
        if (right < n && height[right] < height[left]) {
            sum += height[left] - height[right];
            right++;
        }
        if (right < n && height[right] >= height[left] && right - left < 2) {
            left = right;
            right++;
        }
        if (right < n && height[right] >= height[left] && right - left >= 2) {
            maxRain += sum;
            sum = 0;
            left = right;
            right++;
        }
        if (right == n) {
            sum = 0;
            right = left + 2;
            left++;
        }
    }
    return maxRain;
}

我这个代码看似复杂,但是只考虑了一边的大小,如果右边的柱子比左边的柱子小,但是中间又有比右边柱子小的,那么无法得出答案;

所以我们需要顾及两边最矮的柱子来解决问题,代码如下:

       int trap(vector<int>& height) {
        int n = height.size();
        if (n < 3) return 0;
        
        int left = 0, right = n - 1;
        int leftMax = 0, rightMax = 0;
        int ans = 0;
        // 很巧妙的双指针思路,通过不断维护左右两边最高的柱子
        // 来优先判断先去计算哪一边,低的柱子先计算,高的柱子后计算;
        while (left < right) {
            // 判断哪个柱子高
            if (height[left] < height[right]) {
                // 判断是否能积水
                if (height[left] >= leftMax) {
                    // 不能积水就放重置最高的柱子
                    leftMax = height[left];
                } else {
                    // 能积,就做差
                    ans += leftMax - height[left];
                }
                left++;
            } else {
                // 相同的原理
                if (height[right] >= rightMax) {
                    rightMax = height[right];
                } else {
                    ans += rightMax - height[right];
                }
                right--;
            }
        }
        return ans;
    }

(2) 单调栈思路:

这个思路真的不得了,它主要是利用栈来存储横向的数据,然后通过单调栈来排列,找到第一个比他大的值,然后再计算下一个比他小的值,然后高度做差,就是h,水平做差就是w,相乘得到面积。之后就大概差不多这样了。

2、整体代码如下:

    int trap(vector<int>& height) {
        stack<int> st;
        st.push(0);
        int res = 0;
        for (int i = 1; i < height.size(); i++) {
            if (height[st.top()] == height[i]) {
                st.push(i);
            } else if (height[st.top()] > height[i]){
                st.push(i);
            } else {
                while (!st.empty() && height[st.top()] < height[i]) {
                    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;
                        res += h * w;
                    }
                }
                st.push(i);
            }
        }
        return res;
    }

Study time 1.5h

Leave message:

A laugh can be a very powerful thing.

笑可以是一件很有力量的事。 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值