您的位置:首页 > 移动开发

leetCode Trapping Rain Water

2017-07-14 12:24 435 查看


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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法