- 当青训营遇上码上掘金
主题四:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
解法一:暴力求解
解题思路
在1到n-2号柱子的位置上可以接到青豆,第i个柱子可以接到青豆高度的最大值应为左侧柱子的最大值和右侧柱子的最大值之间的较小值 - 第i个柱子的高度。
对于每一个柱子,求出该柱子左侧的最高柱子的高度和右侧的最高柱子的高度,然后就可以得到当前柱子可以存储的青豆的数量。然后如此遍历每一个柱子,累加就可以得出可以存储的青豆的总数量。
代码
int solution(vector<int> &height) {
int n = height.size();
int ans = 0, maxLeft, maxRight;
for (int i = 0; i < n; ++i) {
maxLeft = 0;
maxRight = 0;
for (int j = i; j >= 0; --j) {
maxLeft = max(height[j], maxLeft);
}
for (int j = i; j < n; ++j) {
maxRight = max(height[j], maxRight);
}
ans += min(maxRight, maxLeft) - height[i];
}
return ans;
}
解法二:动态规划
解题思路
在解法一中,每次计算当前柱子可以容纳青豆数量时,都需要重新左侧和右侧最高柱子的高度。
因此可以分别使用两个数组来记录从0到i-1中的最高柱子高度和从n-1到i+1中最高柱子的高度,再遍历计算出每个柱子可以存储青豆的数量,相加即为所得。
代码
int solution(vector<int> &height) {
int n = height.size();
int ans = 0, lMax = 0, rMax = 0, minHeight;
vector<int> left(n), right(n);
for (int i = 0; i < n - 1; ++i) {
lMax = max(height[i], lMax);
left[i] = lMax;
}
for (int i = n - 1; i > 0; --i) {
rMax = max(height[i], rMax);
right[i] = rMax;
}
for (int i = 1; i < n - 1; ++i) {
minHeight = min(left[i], right[i]);
if (minHeight > height[i])
ans += minHeight - height[i];
}
return ans;
}