leetCode Trapping Rain Water

本文介绍了一种雨水收集问题的解决算法,通过寻找塔顶并计算各段间的积水来得出结果,并提供了一种更简单的实现方式,即计算每个位置左右最大高度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



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;
        
    }










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值