LearningRecord
LearningRecord copied to clipboard
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水
思路: 方法一:
- 首先找出整个区域最大的数值,记录位置
- 以位置为中心向左找最大的数值, 计算两个位置的容量,并更新最大值的地址,直到循环结束
- 以位置为中心向右找最大的数值,计算两个位置的容量,并更新最大值的地址,直到循环结束
const trapRainWater = (heights) => {
if (heights.length <= 2) return 0;
let max = -1, maxInd = 0;
let i = 0;
for (; i < heights.length; ++i) {
if (heights[i] > max) {
max = heights[i];
maxInd = i;
}
}
let area = 0, root = heights[0];
for (i = 0; i < maxInd; ++i) {
if (root < heights[i]) root = heights[i];
else area += (root - heights[i]);
}
for (i = heights.length - 1, root = heights[heights.length - 1]; i > maxInd; --i) {
if (root < heights[i]) root = heights[i];
else area += (root - heights[i]);
}
console.log(area)
return area;
}
方法二: 首先从左遍历一遍,找到已左边为基准的高度 再从右边遍历一遍找到以右边为基准的高度, 要能够接住水,就要求左右两边,最小的一边的高度应该比中间的都要大,能接住的水的面积就是这些差值。
const trapRainWater2 = (A) => {
if(A == null || A.length < 3)
return 0;
let localMax = A[0];
let left = Array.from(new Array(A.length));
let right = Array.from(new Array(A.length));
for(let i=0;i<A.length;i++) {
if(A[i] <= localMax)
left[i] = localMax;
else {
localMax = A[i];
left[i] = localMax;
}
}
localMax = A[A.length-1];
for(let i=A.length-1;i>-1;i--) {
if(A[i] <= localMax)
right[i] = localMax;
else {
localMax = A[i];
right[i] = localMax;
}
}
let area = 0;
for(let i=0;i<A.length;i++) {
area += Math.min(left[i], right[i]) - A[i];
}
console.log(area)
return area;
}
方法三 左右两个指针,一头一尾开始遍历,首先找到自己这一边的局部最高点,只要比最高点小就可以装水
const trapRainWater = (A) => {
if (A == null || A.length < 3)
return 0;
//两根指针一头一尾向中间进发
let left = 0;
let right = A.length - 1;
//两个变量存储左右两边的局部最大高度
let leftMax = 0;
let rightMax = 0;
let area = 0;
while (left <= right) {
leftMax = Math.max(leftMax, A[left]);
rightMax = Math.max(rightMax, A[right]);
//小的那边可以存水
if (leftMax <= rightMax) {
if (leftMax > A[left]) {
area += leftMax - A[left];
}
left++;
}
else {
if (rightMax > A[right]) {
area += rightMax - A[right];
}
right--;
}
}
return area;
}