leetCode Trapping Rain Water

来源:互联网 发布:js给select option赋值 编辑:程序博客网 时间:2024/05/16 15:01



1、观察图形,能积水的部分一定是两个塔顶之间,所以可以先找到所有的塔顶list,再算它们之间积水

2、首先找到list最高的两个塔顶firHigh,secHigh,那么它们之间的积水一定是两个顶之间较低的那个sum(secHigh-height[i])。然后可以把list中firHigh,secHigh之间的塔顶拿掉

3、然后再找剩下的塔顶里面最高的highpos,如果highpos在以计算区间左边,那就计算左边新增区间面积,否则就是右边的。


 public int trap(int[] height) {       int count=0;    if(height == null || height.length<3)return 0;    int len = height.length;    List<Integer> list = new ArrayList<Integer>();    if(height[0]>height[1])list.add(0);    for(int i=1;i<len-1;i++)    if(height[i]>=height[i-1]&&height[i]>=height[i+1])    list.add(i);    if(height[len-1]>height[len-2])    list.add(len-1);    if(list.size()<2)return 0;    //拿到了所有高点位置    //Collections.sort(list,Collections.reverseOrder());    int firstHighPos=-1,firstHigh=-1;    int secHighPos=-1,secHigh=-1;    for(int i=0;i<list.size();i++){    if(firstHigh==-1){    firstHighPos=list.get(i);    firstHigh = height[firstHighPos];    }    else if(height[list.get(i)]>firstHigh){    secHighPos=firstHighPos;    secHigh = firstHigh;    firstHighPos=list.get(i);    firstHigh = height[firstHighPos];        }    else if(height[list.get(i)]>secHigh){    secHighPos=list.get(i);    secHigh = height[secHighPos];    }        }//list里面是存的位置int leftPos= -1;int rightPos=-1;    if(firstHighPos<secHighPos){    leftPos= firstHighPos;    rightPos=secHighPos;    }     else{    leftPos=secHighPos ;    rightPos=firstHighPos;    }    //清掉list中left、right之间的pos,不需要了    for(int i=list.size()-1;i>=0;i--){    if(list.get(i)<=rightPos&&list.get(i)>=leftPos ){    list.remove(i);    }    }    count+=cal(height, leftPos,rightPos);        while(list.size()>0){    int HighPos=-1,High=-1;    for(int i=0;i<list.size();i++){    if(height[list.get(i)]>High){    HighPos=list.get(i);    High = height[list.get(i)];    }    }    //更新已计算pos范围    if(HighPos<leftPos){    count+=cal(height, HighPos,leftPos);    leftPos = HighPos;    }    else{    count+=cal(height, rightPos,HighPos);    rightPos = HighPos;    }    //清掉list中left、right之间的pos,不需要了    for(int i=list.size()-1;i>=0;i--){        if(list.get(i)<=rightPos&&list.get(i)>=leftPos ){        list.remove(i);        }        }        }return count;            }    public static int cal(int[] height,int leftPos,int rightPos){    int count=0;    int min = height[leftPos]<height[rightPos]?height[leftPos]:height[rightPos];    for(int j=leftPos+1;j<rightPos;j++){    count+=min-height[j]>0?min-height[j]:0;    }    return count;    }


这种想法比较自然,扫描height也只要O(n),不过需要使用list记录塔顶位置,有额外开销

看了下别人的思路,有一种比较简单,记录每个位置左边最大的高度lefthigh和右边最大的高度righthigh,那么area[i]=min(lefthigh,righthigh)-height[i]

所以只需要扫描height三遍,分别计算出lefthigh[i]和右边最大的高度righthigh[i]和area[i]即可

 public int trap(int[] height) {       int count=0;    if(height == null || height.length<3)return 0;    int len = height.length;    int left = 0;    int right = len-1;    int max=0;    int A[]=new int[len];    int B[]=new int[len];        while(left<len){    if(height[left]>max){    max=height[left];    }    A[left]=max;    left++;    }    max=0;    while(right>-1){    if(height[right]>max){    max=height[right];    }    B[right]=max;        right--;    }    for(int i=0;i<len;i++){    if(A[i]>B[i])    count+=B[i]-height[i];    else    count+=A[i]-height[i];    }return count;            }