LeetCode---42. Trapping Rain Water

LeetCode—42. Trapping Rain Water

题目

https://leetcode.com/problems/trapping-rain-water/description/
给出一个整数数组,每一个元素代表数轴上宽度为1的矩形的高度,,这些矩形紧紧相邻。想象向这些矩形中下雨,现在要求计算可以存储多少雨水。
LeetCode---42. Trapping Rain Water_第1张图片

思路及解法

1.暴力解法
我们分别去计算每个小矩形上面可以存储的雨水,最后将其加和。那么首先就是一个外层循环去遍历每一个矩形。下一步解决确定每个矩形上方有多少雨水的问题,对于每一个矩形,我们需要从两侧向中间逼近,分别找到这个矩形两侧最高的矩形高度,这很容易,确定好这两个值后,再分下面三种情况进行讨论:

  • 两侧的数值a,b,都比要计算的矩形i高,那么矩形i能存储的水量=min[a,b]-height[i]
  • 只有一侧的数值,也就是a或者b比矩形i高,那么村水量为0
  • a,b逗比矩形i低,村水量为0

这种方法是在找规律,然后用代码实现出来,时间复杂度 n2 n 2 ,空间复杂度1,solution里面还介绍了一种动态规划的方法,是用空间换取时间,下面介绍

2.动态规划
时间复杂度n,空间复杂度n。
整体思路与暴力解发相同,只是调用了C++里max函数找到左右两侧的最大值,并将其放入到新开辟空间的vector中。具体操作可以看下面的代码。

3.双指针法
这种方法其实也是一种找规律的方法,solution里面有一张动态图用来说明具体的思路,大家可以参考。这里只贴出相应的伪代码,很清晰,也很容易写出代码。
LeetCode---42. Trapping Rain Water_第2张图片

代码

暴力解法
class Solution {
    public int trap(int[] height) {
        int left, right;
        int max_left, max_right;
        int water = 0;
        int len = height.length;
        for(int i = 1; i < len-1; i++){
            left = 0;
            right = len-1;
            max_left = height[left];
            max_right = height[right];
            while(left < i){
                if(height[left]>max_left){
                    max_left = height[left];
                }
                left++;
            }
            while(right > i){
                if(height[right]>max_right){
                    max_right = height[right];
                }
                right--;
            }
            if(max_left>height[i] && max_right>height[i]){
                water += (max_left>max_right ? max_right:max_left)-height[i];
            }
        }
        return water;
    }
}
动态规划解法
int trap(vector<int>& height)
{
    if(height == null)
        return 0;
    int ans = 0;
    int size = height.size();
    vector<int> left_max(size), right_max(size);
    left_max[0] = height[0];
    for (int i = 1; i < size; i++) {
        left_max[i] = max(height[i], left_max[i - 1]);
    }
    right_max[size - 1] = height[size - 1];
    for (int i = size - 2; i >= 0; i--) {
        right_max[i] = max(height[i], right_max[i + 1]);
    }
    for (int i = 1; i < size - 1; i++) {
        ans += min(left_max[i], right_max[i]) - height[i];
    }
    return ans;
}
双指针法
class Solution {
    public int trap(int[] height) {
        int len = height.length;
        int leftmax = 0, rightmax = 0;
        int left = 0, right = len - 1;
        int ans = 0;
        while(left < right){
            // left小
            if(height[left] < height[right]){
                if(height[left] > leftmax){    // 更新leftmax
                    leftmax = height[left];
                }else{
                    ans += leftmax - height[left];
                }
                left++;
            }else{ //right小
                if(height[right] > rightmax){  // 更新rightmax
                    rightmax = height[right];
                }else{
                    ans += rightmax - height[right];
                }
                right--;
            }
        }
        return ans;
    }
}

你可能感兴趣的:(LeetCode刷题整理)