zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    数据库范式
    服务器防火墙
    Java垃圾回收(GC)机制详解
    Java内存模型
    类加载器
    Java类加载机制
    java虚拟机:Java内存区域及对象
    初识HashMap
    初识LinkedList
    java ArrayList
  • 原文地址:https://www.cnblogs.com/KakagouLT/p/13693952.html
Copyright © 2011-2022 走看看