当青训营遇上码上掘金
主题 4:攒青豆
题目描述:现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
示例 1:
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
示例 2:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
思路
想不出动态规划咋办,看不懂单调栈咋办,双指针也看得云里雾里。这里我们可以用面积减法来解。总面积=青豆面积+柱子面积+空气面积。
以示例2为例:
- 青豆的面积=总的面积-柱子面积-空气面积。
- 总的面积=最高柱子高度*柱子个数。
- 柱子面积=累加(柱子高度)。
- 空气面积=。
如何计算上方空气小块的面积?以为例:
我们可以往右遍历数组,为其下标,每发现柱子高度高于之前记录的,就可以认为发现了一个空气小块,。
S2=高的长度*底的长度=。
从左往右计算左边的空气块,再从右边往左计算右边的空气块。
算法流程
- 1.计算最高柱子高度
- 2.计算总体面积。
- 3.计算柱子总面积。
- 4.从左往右直到最高柱子位置计算空气小块面积。
- 5.从右往左直到最高柱子位置计算空气小块面积。
- 6.计算青豆面积。青豆面积=总体面积-柱子面积-空气面积。
复杂度分析
- 时间复杂度。n是height数组的长度,需遍历两次数组。
- 空间复杂度。只需常量额外内存。
C++代码
#include<iostream>
#include <vector>
using namespace std;
int main() {
int a;
vector<int> height;
while(cin>>a){
height.push_back(a);
if(getchar()=='\n') break;
}
int len=height.size();
int maxh=0,ans=0;
for(int i =0;i<len;i++){
if(height[i]>height[maxh]) maxh=i;
ans-=height[i];
}
ans+=len*height[maxh];
for(int j=0,pos=0;j<=maxh;j++){
if(height[j]>height[pos]){
ans-=(height[maxh]-height[pos])*(j-pos);
pos=j;
}
}
for(int j=len-1,pos=len-1;j>=maxh;j--){
if(height[j]>height[pos]) {
ans-=(height[maxh]-height[pos])*(pos-j);
pos=j;
}
}
cout<<ans<<endl;
return 0;
}