当青训营遇上码上掘金
题目
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
思路:
如图,假设最高的柱子在最右边:我们从最左边的柱子开始遍历(把它的高度设为lmax),遇到比它矮的柱子就把它们之间的高度差用青豆填满,直到遍历到一个比lmax值要高的柱子时,更新lmax的值,如此往复,直到lmax更新为最高柱子的值。
同理,假设最高柱子在最左边,从最右边开始遍历也是一样的过程。看看下面的图:
我们需要确定的就是柱子的最高值,可以用双指针来解决(左边:lmax,右边:rmax)
lmax:左边柱子最高值,初始值为height[l]
rmax:右边柱子最高值,初始值为height[r]
假使开始时 lmax > rmax,固定lmax,rmax从右边开始往左遍历,直到rmax值更新值大于lmax(即 lmax < rmax时),这时固定rmax,lmax开始从左边往右边遍历......直到l==r
过程分析:其实在lmax和rmax值更新的过程中,被固定的一方总是充当最高柱子值的角色,这样保证了当lmax/rmax遍历时,另一边总是存在最高值的
code
C++
#include<iostream>
#include<stdio.h>
#include<vector>
using namespace std;
int getQDnum(vector<int>&);
int main() {
vector<int> height;
int x;
while (cin >> x) {
height.push_back(x);
if (cin.get() == '\n') break;
}
printf("%d",getQDnum(height));
return 0;
}
int getQDnum(vector<int>& height) {
int sum = 0;
int l = 0, r = height.size() - 1;
int lmax = height[l], rmax = height[r];
while (l < r) {
if (lmax > rmax) {
while (height[r] <= rmax && l < r) {
sum += rmax - height[r];
r --;
}
rmax = height[r];
}else {
while (height[l] <= lmax && l < r) {
sum += lmax - height[l];
l ++;
}
lmax = height[l];
}
}
return sum;
}
Go
func getQDnum(height []int) int {
sum := 0
l, r := 0, len(height) - 1
lmax, rmax := height[l],height[r]
for l < r {
if lmax > rmax {
for height[r] <= rmax && l < r{
sum += rmax - height[r]
r --
}
rmax = height[r]
} else {
for height[l] <= lmax && l < r{
sum += lmax - height[l]
l ++
}
lmax = height[l]
}
}
return sum
}