42. 接雨水【困难】未完


链接

题目描述

在这里插入图片描述

1.按行接 O ( M ∗ N ) O(M*N) O(MN) 【不用看】

从第一行遍历到最后一行,统计雨水的数量
对于第 i 行:如果当前高度 >= i ,res += temp , temp = 0
如果当前高度 < i, temp ++

class Solution {
    public int trap(int[] height) {
        if(height == null || height.length <= 2){
            return 0;
        }
        int maxNum = getMax(height);
        int res = 0;
        for(int i = 1 ; i <= maxNum ; i++){//从第一层开始加到最高层
            int temp = 0;//记录每一层一共有多少雨水
            boolean isStart = false;
            for(int j = 0; j < height.length ;j++ ){//从数组中每个位置开始遍历
                if(isStart && height[j] < i){
                    temp++;
                }
                if(height[j] >= i){
                    res += temp;
                    temp = 0;
                    isStart = true;
                }
            }
        }
        return res;
    }
    
    private int getMax(int[] height){
        int max = height[0];
        for(int i = 0; i < height.length;i++){
            max = Math.max(max,height[i]);
        }
        return max;
    }
}

时间复杂度: O ( m ∗ n ) O(m*n) Omn, 最大的数是 m, 长度为 n
空间复杂度: O ( 1 ) O(1) O1

leetcode 超时

2. 按列接 O ( N 2 ) O(N^2) O(N2)

对于每一列来说,能装的雨水是左边最高的墙和右边最高的墙的最小值-当前列的高度(墙的高度要 >= 当前列的高度,不然就接不了雨水了)

class Solution {
    public int trap(int[] height) {
        if(height == null || height.length <= 2){
            return 0;
        }
        int res = 0;
        for(int i = 1; i < height.length-1;i++){//对于每一列,要找出左边最高的墙,和右边最高的墙
            //找到左边最高的墙
            int leftTop = height[0];
            for(int m = 0; m < i; m++){
                leftTop = Math.max(leftTop,height[m]);
            }
            //找到右边最高的墙
            int rightTop = height[height.length-1];
            for(int n = height.length-1 ; n > i; n-- ){
                rightTop = Math.max(rightTop,height[n]);
            }
            //判断一下左边最高的墙和右边最高的墙是否比当前列的高度大
            if(leftTop >= height[i] && rightTop >= height[i]){
                //当前列能装的雨水
                int cur = Math.min(leftTop,rightTop)-height[i];
                res += cur;
            }
            
        }
        return res;
    }
}

时间复杂度: O ( N 2 ) O(N^2) O(N2)
空间复杂度: O ( 1 ) O(1) O(1)

3.动态规划 时间: O ( n ) O(n) O(n) 空间: O ( n ) O(n) O(n)

对于第二问解法的优化
我们注意到,对于每一列,都求左边最高的墙和右边最高的墙,都是重新遍历一次高度
用两个数组:
max_left[i] : 代表左边最高的墙的高度(不包括自己)
max_right[i] : 代表右边最高的墙的高度(不包括自己)

max_left[i] = max(max_left[i-1],height[i])
max_right[i] = max(max_right[i+1],height[i])

class Solution {
    public int trap(int[] height) {
        if(height == null || height.length <= 2){
            return 0;
        }
        int res = 0;
        //生成左边最高墙
        int[] max_left = new int[height.length];
        for(int i = 1; i < height.length-1 ;i++){
            max_left[i] = Math.max(max_left[i-1] , height[i-1]);
        }
        //生成右边最高墙
        int[] max_right = new int[height.length];
        for(int i = height.length-2 ; i > 0 ;i--){
            max_right[i] = Math.max(max_right[i+1] , height[i+1]);
        }
        //对每个列,计算结果
        for(int i = 1; i < height.length-1 ;i++){
            int cur = Math.min(max_left[i],max_right[i])-height[i] > 0 ? Math.min(max_left[i],max_right[i])-height[i] : 0 ;
            res += cur;
        }
        
        return res;
    }
}

时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( n ) O(n) O(n),用来保存每一列左边最高的墙和右边最高的墙。

4.双指针

动态规划中,对空间复杂度进行进一步的优化

由于:
max_left[i] = max(max_left[i-1],height[i])
max_right[i] = max(max_right[i+1],height[i])

我们发现可以用一个变量来表示左边最高的高度,再用一个变量表示右边最高的高度
在这里插入图片描述

class Solution {
    public int trap(int[] height) {
        if(height == null || height.length <= 2){
            return 0;
        }
        int res = 0;
        //左右指针
        int left = 1;
        int right = height.length-2;
        
        int left_max = height[0];//左指针左边最高的柱子
        int right_max = height[height.length-1];//右指针右边最高的柱子
            
        //每次计算的是 left 指针 或者 right 指针指向的柱子的雨水
        while(left <= right){
        	//如果 left指针 左边最高 < right指针 右边最高,根据木桶原理,我们现在计算 left指针 的雨水
            if(left_max < right_max){
                int cur = left_max - height[left] > 0 ? left_max - height[left] : 0;
                left_max = Math.max(left_max,height[left]);
                res += cur;
                left++;
            }else{
                int cur = right_max - height[right] > 0 ? right_max - height[right] : 0;
                right_max = Math.max(right_max,height[right]);
                res += cur;
                right--;
            }
        }
        
        return res;
    }
}

时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( 1 ) O(1) O(1)

5.栈(联想【括号匹配】)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值