[LeetCode]42. 接雨水(双指针,DP)
题目
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/trapping-rain-water
题解
思路1
- 按列求,对于每一列,若Math.min(左边最高值,右边最高值)>当前列高度,则高度差等于当前列接的雨水。
- 用DP优化,提前求出lMax、rMax数组,然后DP。时间复杂度O(n),空间复杂度O(n)
思路2(较优,直接看这个)
- 使用双指针,可以只遍历一次,因为当前列是由“Math.min(左边最高值,右边最高值)”决定的,所以若能确定哪边的最高值更小,则有哪边的最高值就可以了,不需要两边的最高值都知道。
- 由此,“我们可以认为如果一端有更高的条形块(例如右端),积水的高度依赖于当前方向的高度(从左到右)。当我们发现另一侧(右侧)的条形块高度不是最高的,我们则开始从相反的方向遍历(从右到左)。”
- lMax,rMax由变量维护,分别表示当前左指针左边的最大值,右指针右边的最大值。代替了数组。故空间复杂度优化至O(1)。
思路1代码(时间复杂度O(n),空间复杂度O(n))
class Solution {
public int trap(int[] height) {
if(height==null||height.length==0){
return 0;
}
int len=height.length;
int[] lMax=new int[len];
int[] rMax=new int[len];
lMax[0]=0;
rMax[len-1]=0;
for(int i=1;i<len;++i){
lMax[i]=Math.max(lMax[i-1],height[i-1]);
}
for(int i=len-2;i>=0;--i){
rMax[i]=Math.max(rMax[i+1],height[i+1]);
}
int ans=0;
for(int i=0;i<len;++i){
int dif=Math.min(lMax[i],rMax[i])-height[i];
ans=dif>0?ans+dif:ans;
}
return ans;
}
}
思路2代码(较优,时间复杂度O(n),空间复杂度O(1))
class Solution {
public int trap(int[] height) {
if(height==null||height.length==0){
return 0;
}
int len=height.length;
int lMax=0;
int rMax=0;
int l=0;
int r=len-1;
int ans=0;
while(l<r){
if(height[l]<=height[r]){
if(height[l]>=lMax){
lMax=height[l];
}
else{
ans+=lMax-height[l];
}
++l;
}
else{
if(height[r]>=rMax){
rMax=height[r];
}
else{
ans+=rMax-height[r];
}
--r;
}
}
return ans;
}
}
posted on 2019-08-11 22:55 coding_gaga 阅读(745) 评论(0) 编辑 收藏 举报