给定一个整形数组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 }