题目链接 传送门
解析
我承认一开始想复杂了,一看答案发现自己是个沙雕。
我一开始居然往极值和差分那个方向去想了,还有就是题目居然标的是困难,唉。
官方题解有四种方案
- 暴力
- 动态规划
- 栈
- 双指针。
前三种,看官方题解就行,属于一点就通的方法。
只是第四种方法即双指针法我不是很熟悉,所以觉得有点嚼头。
我并没有死扣官方的代码,而是在题解点出的方向上自己重构的代码。
思路如下
首先,在写动态规划的时候,我们就发现了几个特点。
第一:left_max[i]>right_max[i]的时候,i点的雨水高度取决于left_max[i],反过来则取决于right_max[i].
第二:left_max[]从左往右总是单调递增的(left_max[i+1]>=left_max[i]),right_max[]从右往左也是单调递增的(right_max[i-1]>=right_max[i])。
所以如果left_max[i]>right_max[j] (i<j)
时
必然有left_max[j]>right_max[j]
,则此时可以确定j点的雨水高度取right_max[j]。
反之可以确定i点雨水高度取left_max[i]。
所以我们就可以不要left_max[]与right_max[]这两个数组了,取而代之的是代表left_max[i] 的变量left_max,和代表right_max[j] 的变量right_max。
设置l,r分别为0,size-1,left_max和right_max分别初始化为height[l],height[r]。
然后如果left_max>right_max,则r点雨点高度确定,计算r点后,r--左滑一格,并更新right_max
反之则l点雨水高度确定,计算l点后l++右滑一格,更新left_max
循环直至l与r相遇。
代码(附带有暴力,动规,双指针三种解法)
class Solution {
public int trap(int[] height) {
// return baoLi(height);
// return dongGui(height);
return doublePoints(height);
}
public int min(int a,int b){
if(a>b)return b;
else return a;
}
//暴力
public int baoLi(int[] height){
int ans=0;
for(int i=0;i<height.length;i++){
int left_max=0,right_max=0;
for(int j=0;j<=i;j++)if(left_max<height[j])left_max=height[j];
for(int j=i;j<height.length;j++)
if(right_max<height[j])right_max=height[j];
ans+=min(right_max,left_max)-height[i];
}
return ans;
}
//动态规划
public int dongGui(int[] a){
if(a==null||a.length==0)return 0;
int ans=0,n=a.length;
int left[]=new int[a.length];
int right[]=new int[a.length];
left[0]=a[0];
for(int i=1;i<n;i++){
if(a[i]>left[i-1])left[i]=a[i];
else left[i]=left[i-1];
}
right[n-1]=a[n-1];
for(int i=n-2;i>=0;i--){
if(a[i]>right[i+1])right[i]=a[i];
else right[i]=right[i+1];
}
for(int i=0;i<n;i++){
ans+=min(right[i],left[i])-a[i];
}
return ans;
}
//双指针
public int doublePoints(int[] a){
if(a==null||a.length==0)return 0;
int ans=0;
int l=0,r=a.length-1;
int left_max=a[l],right_max=a[r];
while(l<r){
if(left_max<right_max){
ans+=left_max-a[l];
l++;
left_max=left_max>a[l]?left_max:a[l];
}
else{
ans+=right_max-a[r];
r--;
right_max=right_max>a[r]?right_max:a[r];
}
}
return ans;
}
}
一点感悟
觉得很多算法都是一点一点改进的,就拿这道题来说,刚开始打死也想不到双指针这样的解法。但是先暴力,优化重复计算问题后就有了动态规划将时间复杂度降到o(n),又通过分析了左右数组的关系来想到用双指针,空间复杂度也降到o(1)了。