Leetcode 42

接雨水这题可谓十分经典了。最近准备多做一些这种直方图相关的题目。

 

单调栈

首先看一下单调栈解法。

int trap(vector<int>& height) {
    stack<int> st;
    int ans = 0;
    int i = 0;
    while(i < height.size()){
        while(!st.empty() && height[i] > height[st.top()]){
            int oritop = st.top();
            st.pop();

            if(st.empty()) break;
            int newtop = st.top();
            int fillHeight = min(height[i], height[newtop]) - height[oritop];
            int distance = i - newtop - 1;
            ans += distance * fillHeight;
        }
        st.push(i);
        i += 1;
    }
    return ans;
}

 

为什么说这是一个单调栈呢?因为在访问某个柱子之前,前面的柱子一定已经把小于它的那些柱子给 pop 掉了,只留下一个单调递减的栈。

 while(!st.empty() && height[i] > height[st.top()]) 

 

所以当我们访问黄色柱子的时候,前面出现过的非单调柱子排列,已经在处理中被灌满水了。

 

 

 

 

现在我们又遇到一个递增的情况,此时我们需要做的是,找出栈顶柱子(红色)和栈顶之下的柱子(绿色)。

 由于栈是单调递减的,因此绿色柱子的高度一定大于等于红色柱子

所以黄色柱子和绿色柱子之间可以灌水(深色部分),灌到红色柱子的高度以上。

 

当然,绿色柱子不一定大于黄色柱子的高度。这时我们就可以再次循环,填补到更高,直到栈满足了单调递减为止。

 

注意,如果栈是空的话,说明没有承接的对手柱子了,那么也就不能灌水。(如图所示,框内的虚空水是无法灌入的。)

 

双指针

双指针法初看之下可能有点奇怪。啊,这也行?

 

首先我们介绍一个朴素的方法。

我们从左往右,每个柱子存储的虚空水高度记为其左边最高柱子。用蓝色记录。

再从右往左,每个柱子存储的虚空水高度记为其右边最高柱子。用黄色记录。

那么,此时着色为绿色的部分,就是实际存储的水。

编程中我们可以记录黄色虚空水和蓝色虚空水的高度,取其小值。

 

 

观察这个方法,我们发现,虚空水为什么不能变成实水?是因为我们并不知道另一边是否有对手柱子承接虚空水。

双指针法的原理就是,我们可以知道另一边至少存在一个柱子,使得我们的虚空水一定会被接住,变成实际的水

 

 

例如,我们的右边指针指向蓝色柱子,左边指针指向黄色柱子。在这两根柱子之间有一根更高的柱子。

当前,我们并不知道灰色柱子的存在。但是,至少我们知道,如果我们以蓝色柱子的高度从左向右填水,那么总会遇到一个柱子可以围挡起来。

当然,当我们移动到了灰色柱子的位置,移动的指针就变成了右边。

总之,以此类推。

 

int trap(vector<int>& height) {
    if(height.size() == 0) return 0;
    int ans = 0;
    int left = 0, right = height.size() - 1;
    int leftmax = height[left], rightmax = height[right];
    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;
}

 

posted on 2020-09-19 00:37  Ricochet!  阅读(154)  评论(0编辑  收藏  举报