主题 4:攒青豆
n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
看到这张图片就能联想到"接雨水"那道题,废话不多说,直接说思路。
思路一
在接雨水那道题中,我们经常用按列计算的思路解题,在攒青豆中同样可以用这个思路。
直接预处理每一个柱子,对于每一个柱子来说,找向左(右)走能被拦下的最大高度,然后再遍历一遍左右数组,找到最小值与h[i]的差,并累加到答案中。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
vector<int> height;
int solve() {
int n = height.size(), ans = 0;
if (n == 0)
return 0;
// 预定义两个数组,存放每个点向左、向右能够围成的最大高度。
vector<int> left_max(n), right_max(n);
// 向左走
left_max[0] = height[0];
for (int i = 1; i < n; i++)
left_max[i] = max(left_max[i - 1], height[i]);
// 向右走
right_max[n - 1] = height[n - 1];
for (int i = n - 2; i >= 0; i--)
right_max[i] = max(right_max[i + 1], height[i]);
// 累加答案
for (int i = 0; i < n; i++)
ans += min(left_max[i], right_max[i]) - height[i];
return ans;
}
int main()
{
int t;
// height = vector<int>{5,0,2,1,4,0,1,0,3};
while(~scanf("%d", &t))
{
height.push_back(t);
}
printf("%d\n", solve());
return 0;
}
思路二
思路二其实是对思路一的一个优化。
可以看到,max_left [ i ] 和 max_right [ i ] 数组中的元素其实只用到了一次。所以可以不用数组,优化空间,只用一个元素就行了。
public int trap(int[] height) {
int sum = 0;
int max_left = 0;
int max_right = 0;
int left = 1;
int right = height.length - 2; // 加右指针进去
for (int i = 1; i < height.length - 1; i++) {
//从左到右更
if (height[left - 1] < height[right + 1]) {
max_left = Math.max(max_left, height[left - 1]);
int min = max_left;
if (min > height[left]) {
sum = sum + (min - height[left]);
}
left++;
//从右到左更
} else {
max_right = Math.max(max_right, height[right + 1]);
int min = max_right;
if (min > height[right]) {
sum = sum + (min - height[right]);
}
right--;
}
}
return sum;
}