当青训营遇上码上掘金
主题 4:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
方案一:直接遍历,暴力求解
- 从左向右遍历数组,判断每一根柱子是否为小容器的边界柱子
- 即找该位置左右两边的最高柱子
- 若存在,且比该位置高,则可以计算出该位置的青豆容量
- 若不存在比该位置高的青豆,则该位置无法接住青豆
方案二:双指针
分析:大容器的容量
- 短板效应:一个容器能接住多少青豆是
由短的那条边决定的 - 观察图片可以看到,整个容器所能装的青豆数量可以分为两个部分:ad之间为第一部分;df之间为第二部分
- 故而可以将求
大容器能装的青豆数量-> 转换成 ->两个小容器能装的青豆数量 - 而每个小容器的容量是由其短边所决定的,所以只需要
找出每个小容器的短边即可
到此为止,问题变成了如何找小容器
- 使用双指针分别指向大容器的两条边a和f
- 长边不动,短边开始向内寻找比他更高的边d
- 如果两条边一样高,则可以从任意一条边开始找
- a与d有构成了一个大容器,重复第二步
- 直至两个指针相遇
c++代码如下:
#include <iostream>
#include <vector>
using namespace std;
int Calculate(vector<int> &hight) {
int left = 0;
int right = hight.size() - 1;
int total = 0;
int tmp = -1;
while (left < right) {
if(hight[left] > hight[right]) {
tmp = right--;
while (hight[right] < hight[tmp]) {
right--;
}
for(int i = right + 1; i < tmp; i++) {
total = total + hight[tmp] - hight[i];
}
} else {
tmp = left++;
while (hight[left] < hight[tmp]) {
left++;
}
for(int i = left - 1; i > tmp; i--) {
total = total + hight[tmp] - hight[i];
}
}
}
return total;
}
int main() {
vector<int> hight = {5, 0, 2, 1, 4, 0, 1, 0, 3};
int total = Calculate(hight);
cout << total << endl;
return 0;
}