【31.接雨水】

59 阅读2分钟

题目

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

输入: height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
解释: 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

题解

方式一:动态规划

i位置储水量 = Math.min(leftMax, rightMax) - height[i]
正常方式是向i的左右两边扫描,这样会重复计算,所以使用动态规划记录每个位置左右的最大值

public int trap(int[] height) {
    int n = height.length;
    int[] leftMax = new int[n]; // 左边最大值
    int[] rightMax = new int[n]; // 右边最大值

    leftMax[0] = height[0];
    for (int i = 1; i < n; i++) {
        leftMax[i] = Math.max(leftMax[i - 1], height[i]);
    }

    rightMax[n - 1] = height[n - 1];
    for (int i = n - 2; i >= 0; i--) {
        rightMax[i] = Math.max(rightMax[i + 1], height[i]);
    }

    int ans = 0;
    for (int i = 0; i < n; i++) {
        ans += Math.min(leftMax[i], rightMax[i]) - height[i];
    }
    return ans;
}

方式二:单调栈

蓄水需要洼地,栈中保存下坡部分,遇到上坡就在栈中找洼地

public int trap(int[] height) {
    Stack<Integer> stack = new Stack();
    int ans = 0;
    for (int i = 0; i < height.length; i++) {
        while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
            int top = stack.pop();
            if (stack.isEmpty()) {
                // 不构成洼地,没有下坡
                break;
            }
            // 计算洼地蓄水量
            int left = stack.peek();
            int w = i - left - 1;
            int h = Math.min(height[left], height[i]);
            ans += w * h;
        }
        // 以height[i]为上坡的洼地已经计算完了
        stack.push(i);
    }
    return ans;
}

方式三:双指针

动态规划使用两个数组可以用两个指针优化

public int trap(int[] height) {
    int left = 0, right = height.length - 1; // 左右指针
    int leftMax = 0, rightMax = 0; // 左右边界
    int result = 0;

    while (left < right) {
        if (height[left] < height[right]) {
            if (height[left] >= leftMax) {
                leftMax = height[left];
            } else {
                result += leftMax - height[left];
            }
            left++;
        } else {
            if (height[right] >= rightMax) {
                rightMax = height[right];
            } else {
                result += rightMax - height[right];
            }
            right--;
        }
    }
    return result;
}

总结

算法:动态规划双指针
数据结构:单调栈