输入: 给定 n 个非负整数数组,表示宽为 1 的柱子的高度。
要求: 计算下雨之后,这些柱子能接住多少雨水。
输出: 一个整数,表示能接住的雨水总量。
思路1:核心是为每个柱子寻找左右更高的边界,并计算两者间的储水量。通过遍历数组,用栈定位左边界,当找到右边界后计算中间柱子的水量并累加。为防止重复计算,将中间柱子的高度更新为边界高度,从而避免后续重复统计。(核心就在于不断修改柱子高度,防止重复计算,但是很绕,远不如思路2简洁明了。)
思路2:计算接水量,只需要找到每个位置上方能容纳水的最小高度限制。这个限制由该位置的左侧最高墙和右侧最高墙中较低的一个决定。
因此:
-
预计算左侧最高墙: 遍历数组,用一个辅助数组记录每个位置向左看,遇到的最高柱子高度。
-
预计算右侧最高墙: 反向遍历数组,用另一个辅助数组记录每个位置向右看,遇到的最高柱子高度。
-
计算并累加水量: 再次遍历数组,对于每个位置,取其左侧最高墙和右侧最高墙中的较小值,然后减去当前柱子的高度。这个差值就是当前位置上方接到的雨水量,将所有位置的雨水量累加即可得到最终答案。
复杂度:
时间复杂度:O(n)
空间复杂度:O(n)
// class Solution {
// public:
// int trap(vector<int>& height) {
// int ans = 0;
// stack<int> tmp;
// int sum = 0;
// for (int i = 0; i < height.size(); i++) {
// if (tmp.empty()) {
// if (height[i] == 0) {
// continue;
// }
// tmp.push(i);
// }
// else if (height[i] >= height[tmp.top()]) {
// while (tmp.size() > 1 && height[i] > height[tmp.top()]) {
// tmp.pop();
// }
// if (height[i] >= height[tmp.top()]) {
// sum = 0;
// for (int j = tmp.top() + 1; j < i; j++) {
// sum += height[j];
// height[j] = height[tmp.top()];
// }
// ans += (i - tmp.top() - 1) * height[tmp.top()] - sum;
// tmp.pop();
// tmp.push(i);
// }
// else {
// sum = 0;
// for (int j = tmp.top() + 1; j < i; j++) {
// sum += height[j];
// height[j] = height[i];
// }
// ans += (i - tmp.top() - 1) * height[i] - sum;
// tmp.push(i);
// }
// }
// else if (height[i] < height[tmp.top()]) {
// tmp.push(i);
// }
// }
// return ans;
// }
// };
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if (n == 0) return 0;
vector<int> left_max(n);
left_max[0] = height[0];
// 1. 从左到右,计算每个i的“左边最高墙”
for (int i = 1; i < n; i++) {
left_max[i] = max(left_max[i - 1], height[i]);
}
vector<int> right_max(n);
right_max[n - 1] = height[n - 1];
// 2. 从右到左,计算每个i的“右边最高墙”
for (int i = n - 2; i >= 0; i--) {
right_max[i] = max(right_max[i + 1], height[i]);
}
int ans = 0;
// 3. 遍历每个柱子,累加它头顶的水
for (int i = 0; i < n; i++) {
ans += min(left_max[i], right_max[i]) - height[i];
}
return ans;
}
};
1628

被折叠的 条评论
为什么被折叠?



