带你手撕单调栈(二)

带你手撕单调栈(二)

思路请看

描述

给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。

img

示例1

输入:

[3,1,2,5,2,4]  

复制

返回值:

5 

复制

说明:

数组 [3,1,2,5,2,4] 表示柱子高度图,在这种情况下,可以接 5个单位的雨水,蓝色的为雨水 

示例2

输入:

[4,5,1,3,2]

返回值:

2 
class Solution {
public:
    /**
     * max water
     * @param arr int整型vector the array
     * @return long长整型
     */
    long long maxWater(vector<int>& arr) {
        // write code here
        /**
            拿到题目先分析
            这个东西,要知道某个地点能蓄水多少就要知道左边比自己高的第一个高度是多少,右边的比自己高的第一个高度是多少
            那么怎么求右边比自己高度是多少
            又发现是一个先进后出的结构,正好要计算左右,那么我们就一正一反的来
        **/
        // 先求右边,这是正向的,处理在while里面
        stack<int> st;
        vector<int> right_high(arr.size(),-1);
        for(int i=0;i<arr.size();i++) {
            while(!st.empty() && arr[st.top()]<=arr[i]) {
                right_high[st.top()] = i;
                st.pop();  // 正的不能直接pop后不管
            }
            
            st.push(i);
        }
        
        // 清空st
        while(!st.empty()) {
            st.pop();
        }
        
        // 开始倒序,加入哨兵节点
        arr.insert(arr.begin(), 0);
        vector<int> left_hight(arr.size());
        for(int i=0;i<arr.size();i++) {
            while(!st.empty() && arr[st.top()]<=arr[i]) {
                st.pop();
            }
            left_hight[i]=st.empty()?-1:st.top()-1; // 这是反向的处理在while外面
            st.push(i);
        }
        left_hight.erase(left_hight.begin());
        arr.erase(arr.begin());
        
//         for(auto value : left_hight) {
//             cout<<value<<" ";
//         }
//         cout<<endl;
//         for(auto value : right_high) {
//             cout<<value<<" ";
//         }
//         cout<<endl;
        
        long long res = 0;
        for(int i=0;i<left_hight.size();i++) {
            if(left_hight[i]>=0 && right_high[i]>=0) {
                res+=(min(arr[left_hight[i]],arr[right_high[i]])-arr[i])*(long long)(right_high[i]-left_hight[i]-1);
            }
        }
        return res;
        
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值