最大接雨量(困难)
题干
给定n个非0整数表示框度为1的柱子的高度图,计算按此排序的柱子,下雨后能接多少的雨水
height = [0,1,0,2,1,0,1,3,2,1,2,1] // 答案: 6

*题目分析
每根柱子的接水量就等于当前柱子左边最高的柱子和当前柱子右边最高的柱子两者高度相互比较取小者,接着用小者的高度减去当前的柱子高度就得到当前柱子的接水量。计算每个柱子的接水量,相加之后就是最终的答案。
这题的关键在于计算的是每根柱子的接水量,而不是多根柱子的总共接水量。
例如:第一根柱子。高度为0,因为是第一个柱子因此左侧最高是自身,右侧最高为第8根(下标为7)柱子。

第6根柱子:高度是0,左边柱子最高为2,右边最高位3,取小者。再减去自身高度,得到接水量为:min(3,2)-0 = 2-0 = 2

解题步骤:
- 计算出每根柱子的左边最高者的高度(包括自身)
- 计算每根柱子的右边最高者的高度(包括自身)
- 根据最值计算每根柱子的接水量,累加得到最终结果。
注:计算过程中必须吧自身加入对比会有偏差
-
1 计算每根柱子的左边最高者的高度(前缀最值)
从左向右遍历,如果是第一个那么最大值就是自身。从第二个开始,比较自身与前一位的最大值,取大者,实现如下:
// 算出前缀最值 let prevMax = [] height.forEach((v,k)=>{ if(k == 0){ prevMax[k] = v }else{ prevMax[k] = max(prevMax[k-1], v) } })
-
2 计算每根柱子的右边最高者的高度(后缀最值)
从右往左遍历(倒序遍历)。需要初始化一下数组元素,因为是倒序赋值。如果是最后一个,最大者就是自身,每个与下一位的最大值比较,取大者。具体实现如下:
// 算出后缀最值 let postMax = [] // 初始化数组 for(let i=0;i<height.length;i++){ postMax[i] = 0 } for(let i=height.length-1;i>=0;i--){ if(i==height.length-1){ postMax[i] = height[i] }else{ postMax[i] = max(postMax[i+1],height[i]) } }
-
3 计算和累加每根柱子的接水量
得到两边的最值之后即可计算每根柱子的接水量了;即:
ans += min(postMax[i],prevMax[i])-selfheight
代码编写:
function reciveRain(){
/* 给定n个非0整数表示框度为1的柱子的高度图,计算按此排序的柱子,下雨后能接多少的雨水 */
let height = [0,1,0,2,1,0,1,3,2,1,2,1] // 答案: 6
// 算出前缀最值
let prevMax = []
height.forEach((v,k)=>{
if(k == 0){
prevMax[k] = v
}else{
prevMax[k] = max(prevMax[k-1], v)
}
})
// 算出后缀最值
let postMax = []
// 初始化数组
for(let i=0;i<height.length;i++){
postMax[i] = 0
}
for(let i=height.length-1;i>=0;i--){
if(i==height.length-1){
postMax[i] = height[i]
}else{
postMax[i] = max(postMax[i+1],height[i])
}
}
// 遍历累加出答案
let ans = 0
height.forEach((v,i)=>{
ans += min(postMax[i],prevMax[i])-v
})
return "最高节水量为:"+ans
}
function min(a,b){
return a > b ? b : a
}
function max(a,b){
return a > b ? a : b
}
document.write(reciveRain()) // 输出: 最高接水量为:6
总结
解题的关键在于要知道如何计算单根柱子的接水量,以及能想到通过求单个柱子来计算总的接水量(局部最优解推出全局最优解)。这可能就需要通过多的联系和积累了。
至于前缀最值和后缀最值的计算,比较简单,可以看前两篇动态规划的前缀最值和后缀最值

本文介绍了如何使用动态规划解决计算柱状图下雨后接水量的问题。通过计算每根柱子的左右两侧最高柱子高度,并求解每根柱子的接水量,最终累加得出总接水量。关键在于求解前缀最值和后缀最值,实现代码中详细展示了这一过程。
718

被折叠的 条评论
为什么被折叠?



