42.接雨水(这道题只会暴力解,看题解拿下)
解法一:动态规划
思想:由于要得到能接的雨水总量,一定是每一个bar位置所能接的雨水的总和,而对于每一个bar而言,其能接水的量无非就是该bar左右两边的bar的最小值减去当前bar的高度,决定了这个bar的位置能接多少水。
所以暴力解就是可以对每一根bar,分别遍历其左右两边bar的最大值,并且得到左右两边最大值的最小值,再减去该bar的高度就可以得出该bar位置的接水量,得到每一根bar的接水量,最后做累加。显然这种方式的复杂度是O(N)。
而动态规划,则用两个数组分别是left_max_arr【i】和right_max_arr【i】来分别保存第i根bar的左右两边的最大值,并且在这一步中,左边的最大值是max(left_max_arr[i-1],height[i]),而右边的最大值是max(right_max_arr[i+1],height[i]),那么我们只需要给定left_max_arr[0] = height[0], right_max_arr[len-1] = height[len-1]的初始值,就可以做递推,在O(n)时间内得到做两两边的最大值数组,最后在遍历一遍原数组,进行求和操作即可。
class Solution {
public:
int trap(vector<int>& height) {
int ans = 0;
int len = height.size();
if(len<3) return 0;
vector<int> left_max_arr(len);
vector<int> right_max_arr(len);
left_max_arr[0] = height[0];
right_max_arr[len-1] = height[len-1];
for(int i=1;i<len;i++){
left_max_arr[i] = max(left_max_arr[i-1],height[i]);
}
for(int i=len-2;i>=0;i--){
right_max_arr[i] = max(right_max_arr[i+1],height[i]);
}
for(int i=0;i<len;i++){
ans += min(left_max_arr[i],right_max_arr[i])-height[i];
}
return ans;
}
};
2. 双指针
双指针的写法是对动态规划解法,在空间复杂度上的优化,由于上述的动态规划解法,需要左右最大值数组来保存每个位置的左右最大值,所以需要O(n)的空间。而双指针,可以通过维护两个做左右指针,来动态的维护每个位置的相对最大值,并且通过这种方式依次记录每个位置的存水量。
class Solution {
public:
int trap(vector<int>& height) {
int ans = 0;
int left = 0,right = height.size()-1;
int maxleft = 0,maxRight = 0;
while(left < right){
maxleft = max(maxleft,height[left]);
maxRight = max(maxRight,height[right]);
if(height[left]<height[right]){
ans += maxleft - height[left];
++left;
}else{
ans += maxRight - height[right];
--right;
}
}
return ans;
}
};
3.单调栈
维护一个单调栈,单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组 height 中的元素递减。
从左到右遍历数组,遍历到下标 i 时,如果栈内至少有两个元素,记栈顶元素为 top,top 的下面一个元素是 left,则一定有 height[left]≥height[top]。如果 height[i]>height[top],则得到一个可以接雨水的区域,该区域的宽度是 i−left−1,高度是 min(height[left],height[i])−height[top],根据宽度和高度即可计算得到该区域能接的雨水量。
为了得到 left,需要将 top 出栈。在对 top 计算能接的雨水量之后,left 变成新的 top,重复上述操作,直到栈变为空,或者栈顶下标对应的 height 中的元素大于或等于 height[i]。
在对下标 i 处计算能接的雨水量之后,将 i 入栈,继续遍历后面的下标,计算能接的雨水量。遍历结束之后即可得到能接的雨水总量。
作者:力扣官方题解
链接:https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int trap(vector<int>& height) {
int ans = 0;
int left = 0, right = height.size() - 1;
int leftMax = 0, rightMax = 0;
while (left < right) {
leftMax = max(leftMax, height[left]);
rightMax = max(rightMax, height[right]);
if (height[left] < height[right]) {
ans += leftMax - height[left];
++left;
} else {
ans += rightMax - height[right];
--right;
}
}
return ans;
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。