当青训营遇上码上掘金
本堂课重点内容
- 撒青豆
题目描述
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
题目分析
如图所示
第一列无法存放青豆
第二列可以存放4 - 0 = 4个青豆
第三列可以存放4 - 2 = 2个青豆
...
可以知道当前列可以存放的青豆数与隔壁左右柱子高度有关
题目解法
- 最直观的思路就是暴力解决
思路是对于每一列,找左边和右边最高的柱子,然后如果左右最高柱子高度的较小值比本列高度要大,那么可以存放相应的青豆,否则无法存放
func gatherGreenBeans(height []int)int {
size := len(height)
sum := 0
for i := 1; i < size - 1; i++ {
leftMax, rightMax := 0, 0
// 找右边最高的柱子
for j := i; j < size; j++){
rightMax = max(rightMax, height[j])
}
// 找左边最高的柱子
for j := i; j >= 0; j--{
leftMax = max(leftMax, height[j]);
}
// 如果自己就是最高的话,
// leftMmax == rightMax == height[i]
sum += min(leftMax, rightMax) - height[i];
}
return sum;
}
缺陷:时间复杂度
优化思路:先计算备忘录用于保存当前列左边和右边最高柱子的高度,使时间复杂度降到O(N),但是空间复杂度提升到了O(N)
- 双指针算法
思路:左右最高柱子的高度值可以“边走边算”,leftMax保存height[0,...,left]最高柱子的高度值,rightMax保存height[right,...,size]最高柱子的高度值,当leftMax<rightMax时,可以计算位于left的列可以存放的青豆数,由于每一列可以存放的青豆数取决于左右最高柱子的较小值,因此不需要关心更大的那一边。
拓展
其实这就是42. 接雨水 - 力扣(LeetCode)题目的变种