【leetcode】42. Trapping Rain Water

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ghscarecrow/article/details/86616951

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.


The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!

Example:

Input: [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6

解题思路1:

暴力枚举法:对于输入的数组height,它每个元素能捕获到的雨水的水量为其最高左坝以及最高右坝的最小值(看到这道题就想起了木桶效应)在减去该元素即该格的高度height[i],按照这种思路进行编程。我们可以推导出一个朴素的枚举算法:

1.对于单独一个数组元素i,定义一个left_max变量记录其左边最高坝的高度,同时定义一个right_max的变量记录其右边最高坝的高度。并分别在 0 — i 以及 i — n 中进行迭代。最后取这两个变量的最小值作为坝高再减去height[i]的值,即为该格可以捕获的水量。

2.重复上述操作进行累加,i的范围为1—n-1原因是最外的格子不可能储水。

具体实现代码如下:

class Solution {
    public int trap(int[] height) {
        int ans = 0;
        int len = height.length;
        
        for(int i = 1;i < len - 1;i++) {
            int left_max = 0,right_max = 0;
            for(int j = i;j >= 0;j--) {
                left_max = Math.max(height[j],left_max);
            }
            
            for(int j = i;j <len;j++) {
                right_max = Math.max(height[j],right_max);
            }
            
            ans += Math.min(left_max,right_max) - height[i];
        }
        
        return ans;
    }
}

时间复杂度为O(n^2),空间复杂度为O(1);

解题思路2:

我们注意到,上述的代码时间复杂度为O(n^2),在leetcode上跑的代码仅仅击败了百分之十几的方案,那么,我们可以对上述代码做什么优化呢?采用空间换时间的策略,我们注意到可以采用动态规划的思想进行编程,定义两个数组left_max,right_max分别记录在下标i位置左边的最高坝,以及右边的最高坝。

具体代码如下:

class Solution {
    public int trap(int[] height) {
        int ans = 0;
        int len = height.length;
        if(len <= 2) {
            return 0;
        }
        int[] left_max = new int[len];
        int[] right_max = new int[len];
        
        left_max[0] = height[0];
        for(int i = 1;i < len - 1;i++) {
            left_max[i] = Math.max(left_max[i-1],height[i]);
        }
        right_max[len-1] =height[len - 1];
        for(int i = len - 2;i > 0;i--) {
            right_max[i] = Math.max(right_max[i + 1],height[i]);
        }
        //累加每个格子的储水量
        for(int i = 1;i <= len - 2;i++) {
            ans += Math.min(left_max[i],right_max[i]) - height[i];
        }
        return ans;
    }
}

优化后的代码时间复杂度为O(n),空间复杂度为O(n)。

解题思路3:

利用双指针技巧

class Solution {
    public int trap(int[] height) {
        int ans = 0;
        int len = height.length;
        int left = 0,right = len - 1;
        int left_max = 0,right_max = 0;
        
        while(left < right) {
            if(height[left] < height[right]) {
                //height[left] >= left_max? (left_max = height[left]):ans += (left_max - height[left]); 
                if(height[left] >= left_max) {
                    left_max = height[left];
                } else {
                    ans += left_max - height[left];
                }
                left++;
            } else {
                //height[right] >= right_max? (right_max = height[right]):ans += (right_max - height[right]);
                if(height[right] >= right_max) {
                    right_max = height[right];
                } else {
                    ans += right_max - height[right];
                }
                right--;
            }
        }
        
        return ans;
    }
}

时间复杂度为O(n),空间复杂度为O(1)

猜你喜欢

转载自blog.csdn.net/ghscarecrow/article/details/86616951