给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。(数组以外的区域高度视为0)
数据范围:数组长度
,数组中每个值满足
,保证返回结果满足
要求:时间复杂度
[3,1,2,5,2,4]
5
数组 [3,1,2,5,2,4] 表示柱子高度图,在这种情况下,可以接 5个单位的雨水,蓝色的为雨水 ,如题面图。
[4,5,1,3,2]
2
function maxWater( arr ) {
const size = arr.length;
let maxH = arr[0];
let maxIdx = 0;
let sum = 0;
const topList = arr.map((v, idx) => ({ v, idx })).sort((i1, i2) => {
const v1 = i1.v, v2 = i2.v;
const o1 = i1.idx, o2 = i2.idx;
return (v1 !== v2
? (v1 < v2 ? 1 : -1)
: (o1 < o2 ? -1 : 1)
);
});
const getWaterV = (startIdx, endIdx) => {
const startH = Math.min(arr[startIdx], arr[endIdx]);
let sum = 0;
for (let i = startIdx + 1; i < endIdx; i++) {
const v = startH - arr[i];
sum += v;
}
return sum;
};
const isRestLowerThenMe = (startIdx) => {
const curH = arr[startIdx];
const size = topList.length;
let result = true;
// 查找 top 列表中值比当前值大的是否位于待检查元素左侧(index < startIdx);
for (let i = 0; i < size; i++) {
const {v, idx} = topList[i];
if (v > curH && idx > startIdx) {
result = false;
break;
}
if (idx === startIdx) {
break;
}
}
return result;
};
for (let i = 1; i < size; i++) {
const h = arr[i];
const isHigherThenMax = h >= maxH;
if (isHigherThenMax || isRestLowerThenMe(i)) {
sum += getWaterV(maxIdx, i);
maxH = h;
maxIdx = i;
}
}
return sum;
} 装水的多少取决于左右两边高度的最小值lmax和rmax,如果左边矮,这从左边开始+1的位置一定能装lmax-arr[i]的水且只能装怎么多水,右边rmax保证一定能装怎么多不会从右边溢出,左边lmax保证只能装怎么多否则会从左边溢出
function maxWater( arr ) {
if (arr.length <= 2) return 0;
let l = 0, r = arr.length-1, lmax = 0, rmax = 0, res = 0;
while(l < r) {
lmax = Math.max(arr[l], lmax);
rmax = Math.max(arr[r], rmax);
if (lmax < rmax) {
res += lmax - arr[l++];
} else {
res += rmax - arr[r--];
}
}
return res;
}
function maxWater( arr ) {
// write code here
let sum = 0 , lMax = [] , rMax = [] , row = arr.length;
for(let i=0 ; i < row ; i++)
{
lMax[i] = Math.max(lMax[i-1] || 0,arr[i]);
rMax[row-i-1] = Math.max(rMax[row-i] || 0,arr[row-i-1]);
}
for(let i=1 ; i < row-1 ; i++)
{
sum += Math.min(rMax[i] , lMax[i]) - arr[i];
}
return sum;
} function maxWater( arr ) {
// write code here
if(arr == null || arr.length<3) return 0
let l = 0,r = arr.length-1, area = 0
let min = Math.min(arr[l],arr[r])
while(l<r){
if(arr[l]<arr[r]){
l++
if(arr[l]<min){
area += min - arr[l]
}else {
min = Math.min(arr[l],arr[r])
}
}else{
r--
if(arr[r]<min){
area +=min-arr[r]
}else {
min = Math.min(arr[r],arr[l])
}
}
}
return area
}