LeetCode42、接雨水

本文详细解析了LeetCode上的雨水收集问题,提供了四种不同的解决方案:纵向遍历、水平遍历、动态规划及双指针法,并分析了每种方法的时间与空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

https://leetcode-cn.com/problems/trapping-rain-water/
在这里插入图片描述

解法

解法一:超时无法AC(纵向遍历)

从底部向上,计算每个层的积水,层数为最大的数,每次要维护一个start和end

class Solution {
    public int trap(int[] height) {
        //一层一层的计算
        //维护一个层数,和计算的雨水
        if(height==null ||height.length<3) return 0;

        int res = 0;
        int max = 0;
        for(int i=0;i<height.length;i++){
            if(max<height[i]){
                max = height[i];
            }
        }
        for(int i=0;i<=max;i++){//层数,层数是最大值
            res +=find(height,i);
        }
        return  res;

    }
    /*
    *返回第i层的积水数
    */
    public int find(int[]height,int high){
        int start=-1,end=-1;
        //必须大于当前的层数的值,这之间的柱子才可能有积水
        for(int i=0;i<height.length;i++){
            if(height[i]>high){
                start = i;
                break;
            }
        }
        for(int j=height.length-1;j>0;j--){
            if(height[j]>high){//0我就要找比他大的
                end = j;
                break;
            }
        }
        if((start!=-1 && end!=-1) && start<end){
            //满足条件则有积水
            int res = 0;
            for(int i=start;i<end;i++){
                if(height[i]<=high){//小于当前的层数,则
                    res++;
                }
            }
            return res;
        }
        return 0;
    }
}

解法二:单个格子的方法(水平遍历)

上面的算法我们是从纵向的维度去思考的,现在我们应该从水平的维度去看,计算每个格子可能存储的积水的高度,每次仅计算一个格子上的积水的单位

class Solution {
    public int trap(int[] height) {
        //一个格子一个格子的计算
        if(height==null ||height.length<3) return 0;

        int res = 0;
        for(int i=1;i<height.length-1;i++){//从1开始才有积水
            int maxLeft = 0,maxRight = 0;
            for(int j=i-1;j>=0;j--){
                maxLeft = Math.max(maxLeft,height[j]);
            }
            for(int j=i+1;j<height.length;j++){
                maxRight = Math.max(maxRight,height[j]);
            }
            int min = Math.min(maxRight,maxLeft);
            if(min - height[i]<=0)//每个格子能积多少水
                continue;//不能积水
            else  res += min-height[i];
        }
        return  res;

    }

}

在这里插入图片描述

时间复杂度达到了O(n*n),空间复杂度O(1),注意在查找左右两边上耗费了时间,有些时候根本不需要更新该高度,所以我们可以提前存储这些值

解法三:动态编程
使用一个rightMax数组来存储i往右的最大高度柱子,使用一个leftMax数组来存储i往左边的最大高度柱子。

class Solution {
    public int trap(int[] height) {
        //一个格子一个格子的计算其上的积水单位
        if(height==null ||height.length<3) return 0;

        int res = 0;

        int[]leftMax = new int[height.length];
        int[]rightMax = new int[height.length];
        leftMax[0] = height[0];
        rightMax[height.length-1] = height[height.length-1];

        //使用一个rightMax来存储i往右的最大高度柱子 使用一个leftMax来存储i往左边的最大高度柱子
        for(int i=1,j=height.length-2;i<height.length && j>=0;i++,j--){
            leftMax[i] = Math.max(height[i],leftMax[i-1]);
            rightMax[j] = Math.max(height[j],rightMax[j+1]);
        }
        for(int i=1;i<height.length;i++){
            int min = Math.min(leftMax[i],rightMax[i]);
            if(min - height[i]<=0)//每个格子能积多少水
                continue;//不能积水
            else  res += min-height[i];
        }

        return  res;

    }

}

在这里插入图片描述

解法四:双指针法
我们使用双指针,方法二里面,大的哪个值决定了我们的遍历方向

  • 比如右边的值大,我们则计算左边的柱子上的积水单位即可。
    因为左边的小,我们知道左边更有可能存在积水单位
    右边指针不动,左边指针动,计算完一个柱子
  • 反之,左边指针不动,右边指针动
class Solution {
    public int trap(int[] height) {
        //一个格子一个格子的计算其上的积水单位
        if(height==null ||height.length<3) return 0;

        int res = 0;

       int left = 0;int right = height.length-1;
       int leftMax = height[0],rightMax=height[right];
       //双指针
       while(left<right){
           //判断哪个大
           if(height[left]<height[right]){
               //我们则计算左边的柱子的积水
               if(height[left]>leftMax ){//没有积水,当前的left柱子上
                    leftMax=height[left];

               }else//有积水
                    res+=leftMax-height[left];

                //左边指针移动一位
                  left++;

           }else{
                //我们则计算右边的柱子的积水
               if(height[right]>rightMax ){//没有积水,当前的right柱子上
                    rightMax=height[right];

               }else//有积水
                    res+=rightMax-height[right];

                //右边指针移动一位
                  right--;
           }
       }
        return  res;

    }

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨夜※繁华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值