42 -Trapping Rain Water 接雨水
42 -Trapping Rain Water 接雨水
问题描述
链接:https://leetcode.com/problems/trapping-rain-water/description/
Given
nnon-negative integers representing an elevation map where the width of each bar is1, 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
延伸
- 可以使用双指针法将空间复杂度进一步降低为O(n)

浙公网安备 33010602011771号