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

672 阅读2分钟

当青训营遇上码上掘金--主题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 个单位的青豆。

分析

首先,观察题目我们可以发现,能接住豆子主要是靠左右两边较高的柱子做‘边’形成“凹槽”。且接住豆子的多少取决于两个‘边’中较矮的那个。故该题我们可以通过遍历数组,查找能形成“凹槽”的柱子的两个‘边’,从而计算接住的豆子。

例如,‘2’柱子,左侧柱子中最高的是‘5’,右侧柱子中最高的是‘4’,形成凹槽。两个边中较矮的那个为‘4’,故该柱子上方能装的青豆为4-2=2个单位的青豆。 '4'柱子左侧最高为'5',右侧没有比它自己更到的柱子了,多以无法形成”凹槽“,接豆子数为0。

需注意,左右两侧的柱子只能当边,无法做底部。故我们计算的柱子只需从1~length-1即可。

代码实现

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

int solution(vector<int> &height){
	//计数 
	int sum=0;
	//两侧柱子只能当边,无法做底部,故循环条件为1~length-1
	for(int i=1;i<height.size()-1;i++){
            //maxleft表示左侧最高的柱子,初始值设为最左侧柱子 。同理,右侧为maxright 
            int maxleft=height[0];
            int maxright=height[height.size()-1]; 
            //循环左侧查找最大的柱子
            for(int j=1;j<i;j++){
                    if(height[j]>maxleft){
                            maxleft=height[j];
                    }
            }
            //同理,循环右侧查找最高柱子
            for(int j=i+1;j<height.size()-1;j++){
                    if(height[j]>maxright){
                            maxright=height[j];
                    }
            }
            //比较两个‘边’,取最小值
            int minmax=min(maxleft,maxright);
            //两‘边’需要高于当前柱子才能形成“凹槽”
            //接豆子高度即为'边'中较低柱子的高度-当前柱子的高度 
            if(height[i]<minmax){
                    sum+=minmax-height[i];
            } 	 
	}
	return sum;
}

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

当然此种方法最为简单易懂,使用其他算法的方法也还有很多,小伙伴们一起去发现吧~