LC42.接雨水

  1. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:
LC42.接雨水_第1张图片

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105

题解
自己能想到的解法:双指针法,思路是左右指针从头尾开始,如果都大于0,就取较小者作为存水的高度,然后再遍历中间的位置,如果小于这个高度的就能存水,加上这个高度差;之后重复这个过程,左右指针开始收缩,找比上一轮高度更高的高度,因为如果小于的话已经遍历过了,如果找得到的话就遍历中间的所有位置,找出这个高度能存的水(高度是h-oldHeight,因为oldHeight在之前已经算过了),时间复杂度是O(n²)

看了题解之后,发现还有动态规划和单调栈解法,这两种解法就讲一下思路,不敲代码了
动态规划:创建两个数组来记录在某个位置它的左边最高高度和右边最高高度,然后这两个最高高度的较小值减去这个位置本身的高度就是这个位置能存的水的高度,然后遍历相加即可

单调栈:从左到右开始遍历,从栈头到栈尾是高度从小到大的顺序,如果符合这个顺序就压入栈,如果要插入的元素大于栈头元素,说明形成凹槽可以存储雨水,就用左右元素的较小值减去中间元素mid的高度即是能存雨水的高度

class Solution {

    public int trap(int[] height) {
        int h; //遍历的时候记录能存水的高度
        int oldHeight=0; //保存上一轮遍历的时候存水的高度
        int left=0;
        int right=height.length-1;
        int water=0;
        while(left<right){
            while(left<right&&height[left]<=oldHeight){
                left++;
            }
            while(left<right&&height[right]<=oldHeight){
                right--;
            }
            h=Math.min(height[left],height[right]);
            for(int i=left+1;i<right;i++){
                if(height[i]<h){
                    if(height[i]>oldHeight){
                        water+=h-height[i];
                    }
                    else{
                        water+=h-oldHeight;
                    }
                }
            }
            oldHeight=h;
        }
        return water;
    }
}

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