Leetcode: 42 Trapping Rain Water

解法1:

对于每个位置能储存的水量是,取左面的最高档位,右面的最高档位之中较小的那个,再减去当前的档位即可,所以最直观的解法如下:

class Solution {
    public int trap(int[] height) {
        int sum = 0,left=0,right=0,now=1,maxl=0,maxr=0;
        int n = height.length;
        while(now<n-1)//开头和结尾的地方不会存水
        {
        	
        		left = now;
        		right = now;
        		maxl = now;
        		maxr=now;
        		while(left>=0)
        		{
        			if(height[left]>height[maxl])
        				maxl=left;
        			left--;
        		}
        		while(right<n)
        		{
        			if(height[right]>height[maxr])
        				maxr=right;
        			right++;
        		}
        		if( height[maxl]>height[now] &&  height[maxr]>height[now])
        			sum+=Math.min(height[maxl], height[maxr])-height[now];
        		now++;
        }
        return sum;
    }
}
但是上面那种做法时间复杂度是O(N^2),时间主要消耗在找左右两个侧最大档位上,每次考虑当前容水量时都要去遍历查找一次,所以可以从这方面入手优化。

优化1:

可以先从左往右遍历一遍,记录在一个新数组中每个档位左面最大的档位,然后从右往左遍历一遍,记录在另一个数组中每个档位右面最大的档位,并且求出当前档位的存水量,最后将存水量累计起来即可。

class Solution {
    public int trap(int[] height) {
        int sum = 0,n=height.length;
        if(n==0)return sum;
    	int[] leftnum = new int[n];
    	int[] rightnum = new int[n];
    	leftnum[0] = height[0];
    	rightnum[n-1] = height[n-1];
    	for(int i=1;i<n;i++)
    	{
    		if(height[i]>leftnum[i-1])
    			leftnum[i] = height[i];
    		else
    			leftnum[i] = leftnum[i-1];
    	}
    	for(int i=n-2;i>=0;i--)
    	{
    		if(height[i]>rightnum[i+1])
    			rightnum[i] = height[i];
    		else
    			rightnum[i] = rightnum[i+1];
    		sum+=Math.min(leftnum[i], rightnum[i])-height[i];
    	}
    	return sum;
    
    }
}

上述代码进行了两次循环,时间复杂度是O(2*N)

优化2:

可以找两个指针分别从数组的两端开始遍历,每次都取二者较小的那个,看看是否要更新leftmax或rightmax,不更新的话求当前的存水量,然后往中间移动较小的指针。之所以取较小的那个指针往中间移动,是因为较小的那个可能是存水的瓶颈,也就是中间可能有比较小的那个更大的档位,要尽快找到作为max,才能让中间的存水量能求出来。而求当前的存水量时,因为取了最小者,max也同时维护了,那就算中间有比max更大的档位,那当前的max也就是瓶颈了,时间复杂度是O(N)

class Solution {
    public int trap(int[] height) {
        int left = 0, right = height.length - 1, maxleft = 0, maxright = 0, res = 0;        
        while(left < right){
            if(height[left] < height[right]){
                if(height[left] > maxleft)
                    maxleft = height[left];
                else 
                    res += maxleft - height[left];
                left++;
            } else {
                if(height[right] > maxright)
                    maxright = height[right];
                else 
                    res += maxright - height[right];
                right--;
            }
        }
        return res;
    }
}
注:最后一段代码是copy Leetcode某位提交者的代码。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值