难度:困难 日期:2023年5月14
给定 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 个单位的雨水(蓝色部分表示雨水)。
示例 2:输入:height = [4,2,0,3,2,5]
输出:9
方法一:遍历+双指针
思路:从前往后遍历,定义slow fast两个边界量,判断fast>=slow时,fast-slow是否 >1 如果不是则将slow赋值为fast;是 则从slow到fast遍历,用两边哪个高度更低,取更低的那个减去每一个height[i],再相加。
var trap = function(height) {
let slow = 0;
let contain = 0;
for(fast = 1;fast < height.length;fast++){
if(fast-slow>1 && height[fast]>=height[slow]){
let temp = height[slow];
while(slow<fast){
contain += temp-height[slow++]
}
}else if(fast-slow==1 && height[fast]>=height[slow]){
slow = fast;
}
}
let max = height[--fast];
while(fast>slow){
max = Math.max(max,height[fast-1]);
contain += max - height[fast-1];
fast--;
}
return contain;
};
结果
方法二:动态规划
思路:从左向右遍历,找到每一个height[i] 的 最大高度,存入leftMax数组。同理,从右向左遍历,存入rightMax数组。将每一个i位置的leftMax 和 rightMax进行比较,取较小的那个,与height[i]相减,再将结果相加。
var trap = function(height) {
let n = height.length;
if(n==0){
return 0;
}
let arrLeft = new Array(n).fill(0);
arrLeft[0] = height[0];
for(let i = 1;i < n;i++){
arrLeft[i] = Math.max(height[i],arrLeft[i-1]);
}
let arrRight = new Array(n).fill(0);
arrRight[n-1] = height[n-1];
for(let i = n-2;i >= 0;i--){
arrRight[i] = Math.max(height[i],arrRight[i+1]);
}
let contain = 0;
for(let i = 0;i < n;i++){
contain += Math.min(arrLeft[i],arrRight[i])-height[i];
}
return contain;
};
结果
方法三:双指针
思路:解决动态规划两个数组储存空间复杂度较大的问题,设置left,right两个变量,记录左右两边的当前位置。判断两边哪个最大高度比较小,取小的那一边的最大高度减去当前高度,然后那一边的left/right前移。
var trap = function(height) {
let n = height.length;
let left = 0,right = n-1;
let leftMax = height[0];
let rightMax = height[n-1];
let contain = 0;
while(left < right){
leftMax = Math.max(leftMax,height[left]);
rightMax = Math.max(rightMax,height[right]);
if(leftMax>rightMax){
contain += rightMax-height[right--];
}else{
contain += leftMax-height[left++];
}
}
return contain;
};