当青训营遇上码上掘金
这篇文章针对攒青豆的问题,给出解法,参考码上掘金地址
题目
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
解法
动态规划
当前位置可以存放的最大豆子数可以通过如下方式得到:设左边柱子的最大高度为leftMax,右边柱子的最大高度为rightMax,当前位置的柱子高度为h,则当前位置可以存放的最大豆子数为min(leftMax,rightMax)-h。因此只要得到每个位置的leftMax和rightMax即可以算出每个位置可以存储的最大豆子数,然后将结果求和即为可以获得的所有青豆数。计算每个位置的leftMax和rightMax可以使用动态规划法,具体方式如下:
const leftMax = new Array(n).fill(0);
leftMax[0] = height[0];
for (let i = 1; i < n; ++i) {
leftMax[i] = Math.max(leftMax[i - 1], height[i]);
}
const rightMax = new Array(n).fill(0);
rightMax[n - 1] = height[n - 1];
for (let i = n - 2; i >= 0; --i) {
rightMax[i] = Math.max(rightMax[i + 1], height[i]);
}
双指针法
在一边求最左边的最大值和最右边的最大值时就可以把当前位置能装多少豆子算出来
当发现左边的柱子高度比右边高时,就移动右边的指针,因为此时能够知道右指针能存储的最多豆子为rightMax-height[right]
当发现右边的柱子高度比左边高时,就移动左边的指针,因为此时能够知道左指针能存储的最多豆子为leftMax-height[left]
let ans = 0; //ans为要求的答案
let left = 0, right = height.length - 1;
let leftMax = 0, rightMax = 0;
while (left < right) {
leftMax = Math.max(leftMax, height[left]);
rightMax = Math.max(rightMax, height[right]);
if (height[left] < height[right]) {
ans += leftMax - height[left];
++left;
} else {
ans += rightMax - height[right];
--right;
}
}
码上掘金代码地址:code.juejin.cn/api/raw/719…