js一刷(法一)
javascript
var trap = function (height) {
let ans=0;
const n=height.length;
let i=0;
let j=n-1;
let left_max=0,right_max=0;
while(i<j){
left_max=Math.max(left_max,height[i]);
right_max=Math.max(right_max,height[j]);
if(left_max<right_max){
ans+=left_max-height[i];
i++;
}
else {
ans+=right_max-height[j];
j--;
}
}
return ans;
};
js一刷(法二)
javascript
var trap = function (height) {
let ans = 0;
let leftMax = [], rightMax = [];
leftMax[0] = height[0];
rightMax[height.length - 1] = height[height.length - 1];
for (let i = 1; i < height.length; i++)
leftMax[i] = Math.max(height[i], leftMax[i - 1]);
for (let i = height.length - 2; i >= 0; i--)
rightMax[i] = Math.max(height[i], rightMax[i + 1]);
for (let i = 1; i < height.length - 1; i++) {
let left_max = leftMax[i], right_max = rightMax[i];
let s = Math.min(left_max, right_max) - height[i];
ans += s;
}
return ans;
};
核心思想:一开始我想着一大块面积一大块的算,但实现不了。思路来自灵神
将每一索引处看成一个桶,我们要知道他的左边最大高度和 右边最大高度 算出通的面积再次减去索引处本来的高度
javascript
let s = Math.min(left_max, right_max) - height[i];
有两种方法,一种是在遍历前,先用两个数组分别记录每个索引处的左边最大值和右边最大值(法二)这种方法空间复杂度高
第二种是双指针,边算最大高度边做累加,对于左边,我们可以明确知道左边的最大高度,但这时候不知道右边,怎么办呢,如果此时left_max<right_max,就可以用于计算了,右边同理
这种方法需要注意循环终止的条件是i<j,而不是i!=j,因为i和j可能会刚好错过,导致无限循环
算法核心
javascript
left_max=Math.max(left_max,height[i]);
right_max=Math.max(right_max,height[j]);
leftMax[i] = Math.max(height[i], leftMax[i - 1]);
rightMax[i] = Math.max(height[i], rightMax[i + 1]);
长得有点像递归