当青训营遇上码上掘金
主题4 题目 现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
个人想法通过计算每一列最多可以攒到的青豆个数相加即可得到答案
解法1 暴力搜索
遍历数组中的每一个数 ,找到其左侧最大的高度和右侧中的最大高度 ,找到之后,用左右最大高度的较小者减去当前的高度,就是当前位置能接的青豆。该方法要循环整个数组,并且每个位置要遍历数组寻找左右柱子高度的最大值,嵌套了一层循环,所以其时间复杂度是O(n^2)。
function zhanqindou_01(arr){
let sum=0
let len=arr.length
for(let i=0;i<len-1;i++){
if(i==0||i==len-1){
continue
}
let leftHeight=arr[i] ,rightHeight=arr[i]
for(let j=i;j<=len-1;j++){
if(arr[j]>rightHeight)rightHeight=arr[j]
}
for(let k=i-1;k>=0;k--){
if(arr[k]>leftHeight)leftHeight=arr[k]
}
let height=Math.min(leftHeight,rightHeight)-arr[i]
if(height>0)sum+=height
}
return sum
}
暴力搜索的优化
我们在找左右最大高度时,不要再遍历时找,通过提前开出两个数组,记下当前位置的左侧最大数值,和右侧最大的数字,具体方法时先构造两个空数组填入0,寻找左侧左侧最大 从数组的第一项开始将第一项左侧最高的数与当前项比较 ,去最大的值。右侧最大值数组同理,这样可以再通过一层循环计算出当前项的攒豆数,算法的时间复杂度为O(n),因为三个循环并不是嵌套关系,空间复杂度也是O(n),只开了三个一维的数组
function zhanqindou_02(arr){
let sum=0
let len=arr.length
let leftHiegthMax=new Array(len).fill(0)
leftHiegthMax[0]=arr[0]
for(let i=1;i<len;i++){
leftHiegthMax[i]=Math.max(leftHiegthMax[i-1],arr[i])
}
let rightHeightMax=new Array(len).fill(0)
rightHeightMax[len-1]=arr[len-1]
for(let j=len-2;j>=0;j--){
rightHeightMax[j]=Math.max(rightHeightMax[j+1],arr[j])
}
for(let k=0;k<len;k++){
sum+=Math.min(leftHiegthMax[k],rightHeightMax[k])-arr[k]
}
return sum
}
最后的答案
let height = [5,0,2,1,4,0,1,0,3]
console.log(zhanqindou_01(height))
console.log(zhanqindou_02(height))