42. 接雨水
题目:
给定
n
n
n 个非负整数表示每个宽度为
1
1
1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
动态规划数组
按列计算雨水面积,当前列的雨水量是左右两边最高柱子中较矮的那根决定的(木桶原理),雨水量等于较矮的那根高度高于当前列高度的量,因此可以维护两个数组,分别表示 i i i列左边最高的柱子和右边最高的柱子,开始时,先初始化两个表,之后再遍历一遍柱子,用变量 s u m sum sum累加总雨水量:
class Solution {
public int trap(int[] height) {
int[] max_left = new int[height.length], max_right = new int[height.length];
int sum = 0;
for (int i = 1; i < height.length - 1; i++) max_left[i] = Math.max(max_left[i - 1], height[i - 1]);
for (int i = height.length - 2; i >= 0; i--) max_right[i] = Math.max(max_right[i + 1], height[i + 1]);
for (int i = 1; i < height.length - 1; i++) {
int min = Math.min(max_left[i], max_right[i]);
if(min > height[i]) sum += min - height[i];
}
return sum;
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n)
三次遍历 h e i g h t height height数组, O ( 3 n ) = O ( n ) O(3n) = O(n) O(3n)=O(n)。
-
空间复杂度: O ( n ) O(n) O(n)
两个表长度的额外空间 O ( 2 n ) = O ( n ) O(2n) = O(n) O(2n)=O(n)。
动态规划双指针
对上面代码的优化,由于动态规划数组中的值每个也只使用了一次,因此可以考虑使用滚动指针, l e f t left left和 r i g h t right right分别从两边向内遍历, s u m sum sum分别累加在 l e f t left left和 r i g h t right right处的雨水面积:
- 开始判断 h e i g h t [ l e f t − 1 ] height[left - 1] height[left−1]和 h e i g h t [ r i g h t + 1 ] height[right + 1] height[right+1]的高度,如果前者小,就更新 m a x l e f t max_left maxleft的值并移动 l e f t + + left++ left++,因为 m a x l e f t max_left maxleft由 h e i g h t [ l e f t − 1 ] height[left - 1] height[left−1]更新而来,所以只要左一直小于右, m a x l e f t max_left maxleft就一定是两边最高柱子中最矮的。
- 如果左边柱子高于右边了,就开始移动 r i g h t right right,只要右边小,同理 m a x r i g h t max_right maxright就一定是两边最高柱子中最矮的。
用这样的方法使得两个指针就很好的一遍遍历完数组了。、
class Solution {
public int trap(int[] height) {
int sum = 0, max_left = 0, max_right = 0, left = 1, right = height.length - 2;
for (int i = 1; i < height.length - 1; i++) {
if(height[left - 1] < height[right + 1]) {
max_left = Math.max(height[left - 1], max_left);
if (max_left > height[left]) sum += max_left - height[left];
left++;
}else {
max_right = Math.max(height[right + 1], max_right);
if(max_right > height[right]) sum += max_right - height[right];
right--;
}
}
return sum;
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n)
一次遍历 h e i g h t height height数组, O ( n ) O(n) O(n)。
-
空间复杂度: O ( 1 ) ) O(1)) O(1))
常数级变量 O ( 1 ) ) O(1)) O(1))。