攒青豆

66 阅读2分钟

当青训营遇上码上掘金

题目如下:

现有 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 个单位的青豆。

从图片中不难看出,每一个位置上可以存放的青豆数取决于他左边最高的柱子和右边最高的柱子,因此我们只需要知道每个位置上左边最大柱子的高度和右边最大柱子的高度,取较小的值减去当前柱子的高度即可作为存放青豆的数量;因此我们只需要记录并不断更新每个位置上的柱子左右两边最大的柱子。由于初始时最高的柱子不知道在哪边,因此不难发现,可以用双指针来解决问题。我们不妨先让左右两边柱子的最大值lm,rm分别等于第一个和最后一个,并在指针移动过程中不断迭代更新最大值,然后用两个指针l,r从两侧开始依次比较。

以所给样例为参考,初始时左边最高的柱子为5,右边最高的柱子为3;当前左边柱子 l > 目前右边最高的柱子rm,则可以说明最高的一个柱子在rm左侧,则r位置上的青豆数记为rm - l;然后我们将r左移到下一个柱子,以此类推,可得出每个位置上的青豆数,统计总数即可;

样例的每个时刻青豆数量如下

左边最高柱子的坐标  累计青豆数  右边最高柱子的坐标
       0               0               7
       0               3               6
       0               5               5
       0               8               4
       0               8               3
       0              11               2
       0              13               1
       0              17               0

完整代码如下

c++

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

const int N = 1e5+10;
int n,h[N],res;

int main()
{
    cin>>n;
    for(int i = 0;i<n;i++) cin>>h[i];
    int l = 0,r=n-1,lm=0,rm=0;
    while(l<r)
    {
        lm = max(h[l],lm);
        rm = max(h[r],rm);
        
        if(h[l]<rm) res += lm - h[l++];
        else res+= rm - h[r--];
    }
    cout<<res;
    return 0;
}

python

n = int(input())
f = list(map(int,input().split()))
lm = 0
rm = 0
l = 0
r = n-1
ans = 0
while(l<r):
    lm = max(f[l],lm)
    rm = max(f[r],rm)
    if f[l] > rm :
        ans+=rm-f[r]
        r-=1
    else:
        ans+=lm-f[l]
        l+=1
print(ans)