给定 n 个非负整数表示每个宽度为 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 个单位的雨水(蓝色部分表示雨水)。
输入:height = [4,2,0,3,2,5]
输出:9
对于下标i,下雨后能积水的话,取左右两端的最小值,并且当前值小于左右两边值。使用动态规划,分别计算当前值的左右两边的最大值,当前值的积水量等于min(leftMax[i],rightMax[i])−height[i]。
class Solution {
public int trap(int[] height) {
//动态规划
int length = height.length;
if(length == 0){
return 0;
}
int[] leftMax = new int[length];
leftMax[0] = height[0];
for(int i = 1;i<length;i++){
leftMax[i] = Math.max(leftMax[i-1],height[i]);
}
int[] rightMax = new int[length];
rightMax[length-1] = height[length-1];
for(int i = length-2;i>=0;i--){
rightMax[i] = Math.max(rightMax[i+1],height[i]);
}
int max = 0;
for(int i = 0;i<length;i++){
max += Math.min(leftMax[i],rightMax[i])-height[i];
}
return max;
}
}
时间复杂度:O(n);
空间复杂度:O(n);
维护两个下标指针,左右指针,向中间遍历,保存两个变量,leftMax和rightMax 的值。
class Solution {
public int trap(int[] height) {
int ans = 0;
int left = 0, right = height.length - 1;
int leftMax = 0, rightMax = 0;
while (left < right) {
leftMax = Math.max(leftMax, height[left]);
rightMax = Math.max(rightMax, height[right]);
if (height[left] < height[right]) {
ans += leftMax - height[left];
++left;
} else {
ans += rightMax - height[right];
--right;
}
}
return ans;
}
}
时间复杂度:O(n);
空间复杂度:O(1);
单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组 height 中的元素递减。
如果栈内至少有两个元素,记栈顶元素为 top,top 的下面一个元素是 left,则一定有height[left]≥height[top]。如果 height[i]>height[top],则得到一个可以接雨水的区域,该区域的宽度是 i−left−1,高度是 min(height[left],height[i])−height[top]。
class Solution {
public int trap(int[] height) {
//栈
int ans = 0;
Deque<Integer> stack = new LinkedList<Integer>();
int n = height.length;
for (int i = 0; i < n; ++i) {
//判断栈是否为空,并且当前值必须大于栈顶值,这样才能形成低洼
while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
//低洼处的下标出栈
int top = stack.pop();
//栈为空 跳出循环
if (stack.isEmpty()) {
break;
}
//取左边的高度,当前值为右边的高度
int left = stack.peek();
//求面积
int currWidth = i - left - 1;
int currHeight = Math.min(height[left], height[i]) - height[top];
ans += currWidth * currHeight;
}
//更新右边值
stack.push(i);
}
return ans;
}
}