LeetCode-42-接雨水

题目

在这里插入图片描述

自己思路

  1. 计算蓝色部分的面积…我一开始还以为计算重合面积。

  2. 最左边不能存雨水,所以必须左右两个都存在才能存雨水。

  3. 构想是建立rain[height.length][max]的数组,但是看题目这样有10^9的复杂度,估计不能AC,但是先写一下。
    在这里插入图片描述

  4. 果然暴力只能318/320,肯定有更好的解法,代码已经放在后面,感觉怎么都得投射到二维,可是二维的话就超过时间复杂度,润去题解。

题解思路

第一种:求每一列有多少雨水

  1. 求每一列会有多少雨水,所以只用关注自己这列的柱子,往左走最高的柱子和往右走最高的柱子即可。
  2. 具体积多少水,需要看两边柱子里较短的那边和自己这列的长度比较。(可知第一列和最后一列必定不会有柱子)
    3.显然可知,只有在较矮的柱子大于自己这列的高度时,才会有雨水积起,积的高度为二者之差。

第二种:动态规划

  1. 第一种方法中,每到一个新的柱子,就需要对左右进行一次遍历查找最高,这样的话有很多重复遍历,可以用动态规划解决这个问题。

第三种:双指针

  1. 首先初始化为left=0,right=height.length-1,left_max=right_max=0
    接雨水的性质,决定了当左右最高的柱子不一样高时,每列是以最短的那根柱子为基准的。
  2. 如果从左往右遍历,那么left_max是可信的,因为已经遍历过了,而此时right_max是不可信的,因为右边柱子没有遍历完,并不确定它是否为右边最高的柱子。
  3. 但如果此时的left_max<right_max,那么无论右边的right_max可不可信,最后的基准一定都是left_max,希望去处理left下标。同理,如果right_max<left_max,那么无论左边的left_max可不可信,最后的基准一定都是right_max,希望去处理right下标。

错误代码(样例通过318/320)

    public static int trap(int[] height) {
        //找到数组中最大值,将其作为高构成二维数组
        int max=0;
        for(int i=0;i<height.length;i++){
            max = Math.max(max,height[i]);
        }
        //建立二维数组 1记录柱子
        int[][] rain=new int[height.length][max];
        for(int i=0;i<height.length;i++){
            for(int j=0;j<max;j++){
                if(j<height[i]) rain[i][j]=1;
            }
        }
        //开始查找不为1的能否存储雨水
        int ans=0;
        for(int i=0;i<height.length;i++){
            for(int j=0;j<max;j++){
                if(rain[i][j]!=1){
                    //往最左找能否找到柱子
                    boolean flag=false;
                    for(int k=i;k>=0;k--){
                        if(rain[k][j]==1){
                            flag=true;
                            break;
                        }
                    }
                    //往右找能否找到柱子
                    boolean flag1=false;
                    for(int k=i;k<height.length;k++){
                        if(rain[k][j]==1){
                            flag1=true;
                            break;
                        }
                    }
                    //都有柱子则可以存雨水 否则不能存
                    if(flag&&flag1) ans++;
                }
            }
        }
        return ans;
    }

代码(第一种方法)

    public static int trap(int[] height) {
        //第一列和最后一列肯定没水 不用考虑
        int ans=0;
        for(int i=1;i<height.length-1;i++){
            //找左边最高的柱子
            int left=-1;
            for(int j=i-1;j>=0;j--) left = Math.max(left,height[j]);
            int right=-1;
            for(int j=i+1;j<height.length;j++) right = Math.max(right,height[j]);
            //找出其中较矮的
            int ai = Math.min(left,right);
            //这个较矮的和本身比较 记住把最高的墙放入考虑
            //如果较矮的大于本身列 则可以存相差列的水
            if(ai>height[i]) ans+=(ai-height[i]);
            //如果小于等于本身列 就没水了
        }
        return ans;
    }

代码(动态规划)

    public int trap(int[] height) {
        //建立往左最高的柱子(不能包括自身)
        int[] left_max = new int[height.length];
        int[] right_max = new int[height.length];
        //开始赋值
        for(int i=0;i<height.length-1;i++){
            if(i==0) left_max[i]=0;
            else left_max[i] = Math.max(left_max[i-1],height[i-1]);
        }
        for(int i=height.length-1;i>0;i--){
            if(i==height.length-1) right_max[i]=0;
            else right_max[i] = Math.max(right_max[i+1],height[i+1]);
        }

        //第一列和最后一列肯定没水 不用考虑
        int ans=0;
        for(int i=1;i<height.length-1;i++){
            //找出其中较矮的
            int ai = Math.min(left_max[i],right_max[i]);
            //这个较矮的和本身比较 记住把最高的墙放入考虑
            //如果较矮的大于本身列 则可以存相差列的水
            if(ai>height[i]) ans+=(ai-height[i]);
            //如果小于等于本身列 就没水了
        }
        return ans;
    }

代码(双指针)

    public int trap(int[] height) {
        int left=0;
        int right=height.length-1;
        int left_max=0;
        int right_max=0;

        int ans=0;

        while(left<=right){
            if(left_max<=right_max){ //此时只用关注left即可
                //此时两者相比矮的一定是left_max
                if(left_max>height[left]) ans+=(left_max-height[left]);
                //更新left_max 因为接下来就进入下一个循环 所以left不用减一
                left_max = Math.max(left_max,height[left]);
                left++;
            }else{
                //此时两者相比矮的一定是right_max
                if(right_max>height[right]) ans+=(right_max-height[right]);
                right_max = Math.max(right_max,height[right]);
                right--;
            }
        }
        return ans;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值