原题链接:
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
题面:
给定
n
个非负整数表示每个宽度为1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。示例 2:
输入:height = [4,2,0,3,2,5] 输出:9提示:
n == height.length
1 <= n <= 2 * 10^4
0 <= height[i] <= 10^5
解题思路:
木桶理论,即每一列能够存储的水有关于左边最高的柱子和右边最高的柱子之间的较小者。
只要能够想到这一点,那么这题就不存在什么难度了。是一道较为简单的hard题呢。
考虑按列求。
height[i]为当前列柱子高度。
设left[i]代表柱子i左边最高的柱子,转移方程为left[i] = max(left[i - 1], height[i - 1]);
设right[i]代表柱子i右边最高的柱子,转移方程为right[i] = max(right[i + 1], height[i + 1])。
先从右往左遍历求出right,至于left,我们在求答案的时候可以顺便求。
设h = min(left[i], right[i]),即左边最高的柱子和右边最高的柱子之间的较小者。如果h大于height[i],则这一列能够存储的水量为h - height[i],如果h不大于height[i],则这一列存储不了水。
代码(CPP):
class Solution {
public:
int left[20010]; // 每个柱子左边最高的柱子
int right[20010]; // 每个柱子右边最高的柱子
/*
木桶理论
*/
public:
int trap(vector<int>& height) {
int n = height.size();
int ans = 0;
// 预处理每个柱子右边最高的柱子
right[n - 1] = height[n - 1];
for (int i = n - 2; i >= 0; i--) {
right[i] = max(right[i + 1], height[i + 1]);
}
// 左边最高的柱子在遍历时顺便求出
left[0] = height[0];
for (int i = 1; i < n - 1; i++) {
// 左边最高的柱子
left[i] = max(left[i - 1], height[i - 1]);
// 左边最高的柱子和右边最高的柱子,较矮的那个
int h = min(left[i], right[i]);
if (h > height[i]) {
ans += h - height[i];
}
}
return ans;
}
};