「青训营 X 码上掘金」主题创作活动-主题4

54 阅读2分钟

「青训营 X 码上掘金」主题创作活动-主题4

当青训营遇上码上掘金

主题4 攒青豆

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

图片.png


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

思路

本题有两种解决办法,一种是使用动态规划的方法,一种是使用单调栈的方法,本文介绍动态规划的解决办法。 每列能够接到的青豆由该列两边的最大高度的最小值决定。因此,可以创建两个数组,分别存储每列左边和右边的最大值,从左往右扫描记录左边最大值,从右往左扫描记录右边最大值,而当前列能存储的青豆数即为两边最大值的最小值减去当前列的高度,最后再将每列能接到的青豆数相加,即为能接到的青豆总数。

#include<iostream>
#include<vector>
#include<cstring> 

using namespace std;

int calculation(vector<int>& height) {
    int n = height.size();
    //存储每列左边和右边最大值 
    int leftMax[n],rightMax[n];
    leftMax[0] = height[0];
    rightMax[n - 1] = height[n - 1];
    //从左往右扫描记录每列左边最大值 
    for(int i = 1;i < n;i++)
        leftMax[i] = max(leftMax[i - 1],height[i]);
    //从右往左扫描记录每列右边最大值
    for(int i = n - 2;i >= 0;i--)
        rightMax[i] = max(rightMax[i + 1],height[i]);
    int sum = 0;
    //每列能接青豆数为左边最大值和右边最大值更小的那个减去当前列的值 
    for(int i = 0;i < n;i++){
        sum += min(leftMax[i],rightMax[i]) - height[i];
    }
    return sum;
}

int main(){
	vector<int> height;
	int temp;
	while(cin>>temp){
		height.push_back(temp);
		//当读入回车时跳出循环 
		if(cin.get()=='\n')
            break;
	}	
	cout<<calculation(height)<<endl;
	return 0;
}