当青训营遇上码上掘金-主题4-攒青豆

60 阅读2分钟

当青训营遇上码上掘金

主题 4:攒青豆

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

方案一:直接遍历,暴力求解

  1. 从左向右遍历数组,判断每一根柱子是否为小容器的边界柱子
  2. 即找该位置左右两边的最高柱子
    1. 若存在,且比该位置高,则可以计算出该位置的青豆容量
    2. 若不存在比该位置高的青豆,则该位置无法接住青豆

方案二:双指针

分析:大容器的容量

  1. 短板效应:一个容器能接住多少青豆是由短的那条边决定的
  2. 观察图片可以看到,整个容器所能装的青豆数量可以分为两个部分:ad之间为第一部分;df之间为第二部分
  3. 故而可以将求大容器能装的青豆数量 -> 转换成 -> 两个小容器能装的青豆数量
  4. 而每个小容器的容量是由其短边所决定的,所以只需要找出每个小容器的短边即可

到此为止,问题变成了如何找小容器

  1. 使用双指针分别指向大容器的两条边a和f
  2. 长边不动,短边开始向内寻找比他更高的边d
    1. 如果两条边一样高,则可以从任意一条边开始找
  3. a与d有构成了一个大容器,重复第二步
  4. 直至两个指针相遇 image.png

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;
}