42. 接雨水 - LeetCode

42. 接雨水

题目链接

暴力枚举

  • 枚举每个点,分别找左边和右边的最大值,二者中较小的就是这个点的深度
  • 每个点深度之和就是结果
class Solution {
    public int trap(int[] height) {
        int len = height.length;
        int ans = 0;
        for(int i = 1; i < len - 1; i++){
            int maxLeft = 0, maxRight = 0;
            for(int j = i; j >= 0; j--)
                maxLeft = Math.max(maxLeft, height[j]);
            for(int j = i; j < len; j++)
                maxRight = Math.max(maxRight, height[j]);
            ans += Math.min(maxLeft, maxRight) - height[i];
        }
        return ans;
    }
}
  • 时间复杂度O(n2),空间复杂度O(n)

预处理

  • 显然上面的方法有优化空间,因为我们没有必要每个点都重新计算左右最大值
  • 我们可以通过预处理的方式,分别用一次循环算出左右最大值
class Solution {
    public int trap(int[] height) {
        int len = height.length;
        if(len == 0) return 0;
        int[] maxLeft = new int[len];
        int[] maxRight = new int[len];
        maxLeft[0] = height[0];
        for(int i = 1; i < len; i++)
            maxLeft[i] = Math.max(maxLeft[i-1], height[i]);
        maxRight[len-1] = height[len-1];
        for(int i = len - 2; i >= 0; i--)
            maxRight[i] = Math.max(maxRight[i+1], height[i]);
        int ans = 0;
        for(int i = 1; i < len - 1; i++)
            ans += Math.min(maxLeft[i], maxRight[i]) - height[i];
        return ans;
    }
}
  • 时间复杂度O(n),空间复杂度O(n)

双指针

  • 能不能用一次循环,就求出结果?
  • 理论上是可行的,因为其实我们可以在一次循环中求出路过的最大值,同时求出当前点的深度
  • 但是,如果只是单向循环,我们没有办法同时找出两边的最大值
  • 因此,我们使用双指针,分别从两边往中间枚举
    • 对于左指针来说,左边的leftMax是可信的,而右边的rightMax是不可信的,因为没有枚举所有的右边高度
    • 但是,当左指针的高度小于右指针的高度时,右边就不可能出现比左边小的rightMax了,即当前点的深度只取决于leftMax,直接计算结果即可
    • 右指针同理,当右指针高度小于左指针时,深度取决于rightMax
class Solution {
    public int trap(int[] height) {
        int len = height.length;
        if(len == 0) return 0;
        int ans = 0;
        int left = 0, right = len - 1;
        int leftMax = 0, rightMax = 0;
        while(left < right){
            if(height[left] < height[right]){
                if(height[left] > leftMax)
                    leftMax = height[left];
                else ans += leftMax - height[left];
                left++;
            } else {
                if(height[right] > rightMax)
                    rightMax = height[right];
                else ans += rightMax - height[right];
                right--;
            }
        }
        return ans;
    }
}
  • 时间复杂度O(n),空间复杂度O(1)
posted @ 2021-02-25 11:50  一天到晚睡觉的鱼  阅读(58)  评论(0)    收藏  举报