「青训营 X 码上掘金」主题创作 | 攒青豆

65 阅读2分钟

当青训营遇上码上掘金。

本题目来自「青训营 X 码上掘金」的主题创作,很有意思的4个选题,因为后端推荐选择主题3或主题4,我选择了主题4进行代码创作。

主题 4:攒青豆

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

image.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]  
输出:17  
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

一道简单的模拟题。

如图所示,能够接住青豆的地方一定是两边高中间低的。例如从第一处0开始(5是边),向右移动,有20更高,可以兜住5 0 2的青豆,2再向右移动,42高,可以兜住5 0 2 1 4之间的青豆;4右边没有比4更高的,所以结束,又从4开始重复操作到最后(作边)。

同时两边(最高边)最低的那一边(minmax)决定了该区域能够攒到的青豆的最高处;但是如同柱子2显示的,该处的青豆的实际高度为4-2=2,其他的地方同理。

于是可以计算出除边外所有的柱子可以接住的青豆个数minmax-height[i],把不是边的每一个的值相加,最终结果即为答案。

题目比较简单,我选择的方法也简单易懂,最后呈现的代码也比较简短,并且在每一句都加了注释,很好理解。

ps.马上掘金的代码创作平台不太会用,反正在vsc里面是跑通了的。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int solution(vector<int> &height){
    int sum=0;
    //两侧柱子不能作底,故底只能取1~n-1
    for(int i=1;i<height.size()-1;i++){
        //maxl表示左侧最高的柱子,初始值设为最左侧柱子 
        int maxl=height[0];
        //maxr表示右侧最高的柱子,初始值设为最右侧柱子 
        int maxr=height[height.size()-1]; 
        //循环左侧查找最高的柱子
        for(int j=1;j<i;j++){
          if(height[j]>maxl){
            maxl=height[j];
          }
        }
        //同理,循环右侧查找最高柱子
        for(int j=i+1;j<height.size()-1;j++){
          if(height[j]>maxr){
            maxr=height[j];
          }
        }
        //比较maxl和maxr,取最小值(木桶原理)
        int minmax=min(maxl,maxr);
        //两边需要高于当前柱子才能形成“凹槽”
        //第i个柱子接豆子高度即为minmax-height[i]
        if(height[i]<minmax){
          sum+=minmax-height[i];
        } 	 
    }
    return sum;
}

int main() {  
  vector<int> height;    
  // int n;
  // cin >> n;
  int x;  
  while(cin >> x){    
    height.push_back(x);    
    if (cin.get() == '\n'){
    	break; 
    }
  }  
  int res=solution(height)
  cout << res << endl; 
  return 0;
}