42 -Trapping Rain Water 接雨水

42 -Trapping Rain Water 接雨水

问题描述

链接:https://leetcode.com/problems/trapping-rain-water/description/

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

给定n个非负的整数 代表相应位置柱子的高度,柱子的宽度为1,求柱子构成的容器中能储存多少雨水?

案例:

Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
Explanation: The above elevation map (black section) 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.

解释:

给定数组height = [0,1,0,2,1,0,1,3,2,1,2,1], 其代表的柱子构成的容器如上所示。上述容器从左到右的高度依次为height数组中相应的数值。

故 该容器能存储的水 为 1+4 + 1 = 6

基本思想

这是一道动态规划的题目,属于一维动态规划。假设height的元素数目为n,定义长度为n的数组dp

  • dp[i] 表示 第i个柱子能盛多少的水。dp[i] 依赖于 [0~i-1]最高的柱子leftmax和 [i~n-1]最高的柱子rightmax,即依赖于左边最高的柱子和右边最高的柱子,其更新规则如下:
    • 如果 min(leftmax, rightmax) < height[i], 说明该柱子高度太高,无法盛水
    • 如果 min(leftmax, rightmax) > height[i], 则 dp[i] = 1 * (min(leftmax, rightmax)-height[i]) 注意柱子的高度为1

构建两个数组left, right, 长度为n,left[i] 表示 height[0~i-1] 中最高的柱子高度;right[i] 表示 height[i+1,n-1]中,最高的柱子,可以将时间复杂度降低为\(o(n)\),空间复杂度为\(o(n)\)

代码

C++

    int trap(vector<int>& height) {
        int size = height.size();
        if (size<=2) return 0;
        vector<int> dp(size, 0);
        vector<int> leftMax(size, 0);
        vector<int> rightMax(size, 0);
        leftMax[1] = height[0];
        rightMax[size-2] = height[size -1]; //构建数组,分别存储height[i]左边最高的柱子和右边最高的柱子
        for(int i=2;i<size;++i) {
            if (height[i-1]>leftMax[i-1]) {
                leftMax[i] = height[i-1];
            } else {
                leftMax[i] = leftMax[i-1];
            }
        }
        for(int i=size-3;i>=0;--i) {
            if (height[i+1] > rightMax[i+1]) {
                rightMax[i] = height[i+1];
            } else {
                rightMax[i] = rightMax[i+1];
            }
        }
        int res = 0;
        for(int i=1;i<(size-1);++i) {
            int temp = min(leftMax[i], rightMax[i]);
            if(temp>height[i]) dp[i] = (temp - height[i]);
            res += dp[i];
        }
        return res;
    }
};

python

    def trap(self, height: List[int]) -> int:
        size = len(height)
        if size <= 2: return 0
        dp = [0] * size
        leftMax = [0] * size
        rightMax = [0] * size
        leftMax[1] = height[0]
        rightMax[size-2] = height[size-1]
        res = 0
        for i in range(2,size):
            leftMax[i] = max(leftMax[i-1], height[i-1])
        for i in range(size-3, 0, -1):   # 如何逆向生成序列
            rightMax[i] = max(rightMax[i+1], height[i+1])
        for i in range(1,size):
            dp[i] = max(0, min(leftMax[i], rightMax[i]) - height[i])
            res += dp[i]
        return res

延伸

  1. 可以使用双指针法将空间复杂度进一步降低为O(n)
posted @ 2024-05-10 21:55  金字塔下的蜗牛  阅读(17)  评论(0)    收藏  举报