1、Leetcode-面试经典150题目16-42. 接雨水
思路:
方法1:动态规划
很显然,在第i个下标处,下雨量取决于左右两边的最大高度的最小值,而接水的量等于下雨量-heigth[i];
所以创建两个长度为n的leftMax和rightMax数组,正向遍历height得到leftMax数组各元素的值,再反向遍历得到rightMax的每个元素的值。
在得到数组leftMax和rightMax的每个元素值之后,那么第i处能接的雨水量等于min(leftMax[i],rigthMax[i])-height[i]
图片来源:leecode
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if(n == 0){
return 0;
}
vector<int> leftMax(n);
leftMax[0] = height[0];
for(int i = 1;i < n;++i){
leftMax[i] = max(leftMax[i-1],height[i]);
}
vector<int> rightMax(n);
rightMax[n-1] = height[n-1];
for(int i = n-2;i>= 0;--i){
rightMax[i] = max(rightMax[i + 1],height[i]);
}
int ans = 0;
for(int i = 0;i<n;++i){
ans += min(leftMax[i],rightMax[i])-height[i];
}
return ans;
}
};
方法2:双指针:
1.由动态规划中的“下雨量取决于左右两边的最大高度的最小值,而接水的量等于下雨量-heigth[i];”得到启发,两个数组可以用双指针和两个变量来替代。
2.维护两个指针left和rigth
3.当两个指针没有相遇时,进行如下操作:
不断更新leftmax和rigthmax的值;
- 如果当前height[left]<height[rigth],则一定有leftMax <rigthMax,下标left处的接水量就是leftMax-height[left],然后left指针继续前进
- 如果height[left] >= height[rigth],则一定有leftMax >= rightMax,下标rigth处的接水量等于rightMax - height[right],rigth指针继续左移
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if (n <= 2) return 0; // 如果数组长度小于等于2,无法形成坑,直接返回0
int left = 0, right = n - 1; // 左右指针
int left_max = 0, right_max = 0; // 左右指针所指位置左右两侧的最大高度
int count = 0; // 接水量
while (left < right) {
if (height[left] < height[right]) { // 左侧低于右侧
if (height[left] >= left_max) { // 当前位置高度大于左侧最大高度
left_max = height[left]; // 更新左侧最大高度
} else { // 当前位置高度小于左侧最大高度,可以接水
count += left_max - height[left]; // 计算接水量
}
left++; // 左指针右移
} else { // 右侧不低于左侧
if (height[right] >= right_max) { // 当前位置高度大于右侧最大高度
right_max = height[right]; // 更新右侧最大高度
} else { // 当前位置高度小于右侧最大高度,可以接水
count += right_max - height[right]; // 计算接水量
}
right--; // 右指针左移
}
}
return count;
}
};
方法3:单调栈
1.还可以使用单调栈的方法,单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组 height\textit{height}height 中的元素递减。
2.从左到右遍历数组,遍历到下标i时,如果栈内至少有两个元素,栈顶元素为top,top下面一个元素是left,如果heigth[left] >height[top],说明找到了一个接雨水的区域,区域宽度为i-left-1,高度是min(height[left],height[i])-height[top]
class Solution {
public:
int trap(vector<int>& height) {
int ans = 0;
stack <int> stk;
int n = height.size();
for(int i = 0;i < n;++i){
while(!stk.empty() && height[i] > height[stk.top()]){
int top = stk.top();
stk.pop();
if(stk.empty()){
break;
}
int left = stk.top();
int currWidth = i-left-1;
int currHeight = min(height[left],height[i])-height[top];
ans += currWidth*currHeight;
}
stk.push(i);
}
return ans;
}
};
知识点总结:数组、动态规划、双指针、单调栈
每日一言:成功的关键在于始终坚持追求目标的过程,而不是目标本身。
2024年4月1日
softdream