42. 接雨水

317 阅读1分钟

题目

image.png

方法1:暴力O(N^2) O(1)

  • 记录每个格子能存水的最高高度
  • 每个格子能存水的最高高度 = 格子左边柱子最高值 和 右边柱子最高值较小的那个值 - 当前格子的柱子高度
  • 遍历到每个格子时,再分别向左向右遍历,寻找最高柱子。
class Solution {
    public int trap(int[] height) {
        int sum = 0;
        for (int i = 0; i < height.length; i++) {
            //找左边最高柱子
            int leftMax = 0;
            for (int j = i; j >= 0; j--) {
                leftMax = Math.max(leftMax, height[j]);
            }
            //找右边最高柱子
            int rightMax = 0;
            for (int j = i; j < height.length; j++) {
                rightMax = Math.max(rightMax, height[j]);
            }
            //计算当前格子存水高度
            int vol = Math.min(leftMax, rightMax) - height[i];
            sum += vol;
        }
        return sum;
    }
}

方法2:动态规划O(N) O(N)

  • 通过dp提前保存左右最高柱子。
//动态规划存最右最长板子,O(N) O(N)
class Solution {
    public int trap(int[] height) {
        int res = 0;
        int length = height.length;
        if (length == 0) return 0;//特判[]输入
        int[] leftMax = new int[length];//存储左侧最高高度
        int[] rightMax = new int[length];//存储右侧最高高度
        leftMax[0] = height[0];
        rightMax[length - 1] = height[length - 1];
        //计算leftMax[],注意for范围
        for (int i = 1; i < length; i++) {
            leftMax[i] = Math.max(leftMax[i - 1], height[i]);//状态转移
        }
        //计算rightMax[],注意for范围
        for (int i = length - 2; i >= 0; i--) {
            rightMax[i] = Math.max(rightMax[i + 1], height[i]);//状态转移
        }
        //计算当前格子存水高度
        for (int i = 0; i < length; i++) {
            int cur = Math.min(leftMax[i], rightMax[i]) - height[i];
            res += cur;
        }
        return res;
    }
}

方法3:双指针 O(N) O(1)

2BA7A85A7B6963E1A65345800E0F8E20.png

image.png

// 双指针,O(N) O(1)
class Solution {
    public int trap(int[] height) {
        int res = 0;
        int length = height.length;
        if (length == 0) return 0;//特判[]输入
        int i = 0, j = length - 1;//注意范围
        int leftMax = height[0], rightMax = height[length - 1];
        while (i < j) {
            if (leftMax > rightMax) {
                res += rightMax - height[j];//一开始,rightMax和height[j]一样
                j--;
                rightMax = Math.max(height[j], rightMax);
            } else {
                res += leftMax - height[i];//一开始,leftmax和height[i]一样
                i++;
                leftMax = Math.max(height[i], leftMax );
            }
        }
        return res;
    }
}

写法2

class Solution {
    public int trap(int[] height) {
        int sum = 0;
        int i = 1, j = height.length - 2;
        int leftMax = height[0], rightMax = height[height.length - 1];
        while (i <= j) {
            if (leftMax < rightMax) {
                sum += Math.max(0, leftMax - height[i]);// 由于后更新max,所以这里可能是负的
                leftMax = Math.max(leftMax, height[i]);
                i++;
            } else {
                sum += Math.max(0, rightMax - height[j]);
                rightMax = Math.max(rightMax, height[j]);
                j--;
            }
        }

        return sum;
    }
}