题目
- 给出一个数组表示宽度为 1, 高度为 num[i] 的柱子,求下雨后,这些柱子能接住多少雨水。据说是字节经典面试题
思路
-
自己朴素的想法 solution1 是:
- 下标从小到大,找到柱子高度从小到大的递增序列,计算这中间可以接的雨水;
- 下标从大到上述找到的最高柱子的下标,同样找递增序列,计算中间可以接的雨水;
-
题目分类是 two-pointer,按照该解法 solution 2 的思路是:
- 分别看柱子的两头,分别记录 left_max 和 right_max
- 若左边的柱子比右边的柱子高,代表右边的柱子高度可以尝试接雨水,right_max - height right,变动 right pointer
- 反义依然,若相等,随便变动一个 pointer
代码
class Solution {
public:
int solution1(vector<int>& height) {
int ans = 0;
vector<int> asc;
// asc
asc.push_back(0);
int n = height.size();
for (int i = 1; i < n; i++) {
if (height[asc.back()] <= height[i]) {
asc.push_back(i);
}
}
int end = asc.back();
int h = height[0];
for (int i = 1; i < asc.size(); i++) {
for (int j = asc[i - 1]; j < asc[i]; j++) {
ans += (h - height[j]);
}
h = height[asc[i]];
}
// desc
asc.clear();
asc.push_back(height.size() - 1);
for (int i = n - 2; i >= end; i--) {
if (height[asc.back()] <= height[i]) {
asc.push_back(i);
}
}
h = height.back();
for (int i = 1; i < asc.size(); i++) {
for (int j = asc[i - 1]; j > asc[i]; j--) {
ans += (h - height[j]);
}
h = height[asc[i]];
}
return ans;
}
int solution2(vector<int>& height) {
int l = 0, r = height.size() - 1, l_max = height[0], r_max = height.back();
int ans = 0;
while (l < r) {
while (l < r && height[l] <= height[r]) {
l_max = max(l_max, height[l]);
ans += l_max - height[l];
l++;
}
while (l < r && height[l] > height[r]) {
r_max = max(r_max, height[r]);
ans += r_max - height[r];
r--;
}
}
return ans;
}
int trap(vector<int>& height) {
//return solution1(height);
return solution2(height);
}
};