LeetCode Algorithms 42. Trapping Rain Water

题目难度: Hard


原题描述:

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.

For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.



题目大意:

        有n条长木块,每条木块的宽度均为1,高度为题目给出的数组中的非负整数。问在这些木块组成的图形之中加水,最多能加多大体积的水?


解题思路:

        一开始对着题目给出的图来想,想错了,以为可以把题目的输入划分成一个个“U”型的部分,即每一部分都是先下降后上升,然后再求每一部分能装水的体积,最后加起来。但是这种方法是不行的,如果有多个“U”连起来且最左和最右都是最高的木块,这样能装水的体积就不止这么少了。

      后来再想才找到了正确的算法。每一次在数组中找两个最大的数,如果有多个相同,则任取一个。假设左边的数是a,右边的数是b,则在a和b之间的数就可以调用getPartWater()函数来计算在这两个数之间能装水的最大值。接着分别对a左边的数和b右边的数递归调用本函数,来获得这两部分能装水的最大值,最后把这三部分能装水的最大值加起来,就是问题的答案。

      其中getPartWater()函数是用来计算两个木块之间能装水的最大值。其主要思想是先求最左和最右木块高度的最小值minHeight,然后用minHeight来填充在这两条木块之间的空隙,用总的面积减去在填充区域之间实际木块的面积,就是能装水的最大值


时间复杂度分析:

        时间复杂度似乎比较难分析?


以下是代码:

public class Solution {
    private int getPartWater(int i , int j , int[] height)
	{
		int barSum = 0;
		int minHeight = Math.min(height[i], height[j]);
		for(int k=i ; k<=j ; ++k){
			barSum += Math.min(height[k], minHeight);
		}
		int ans = (j-i+1)*minHeight - barSum;
		return Math.max(ans, 0);
	}
	
	private int getAns(int[] height , int left , int right)
	{
		int ans = 0;
		int maxValue1 = -1 , maxValue2 = -1;
		int maxIndex1 = 0 , maxIndex2 = 0;
		for(int i=left ; i<=right ; ++i){
			if(height[i]>maxValue1){
				maxValue1 = height[i];
				maxIndex1 = i;
			}
		}
		for(int i=left ; i<=right ; ++i){
			if(height[i]>maxValue2 && i!=maxIndex1){
				maxValue2 = height[i];
				maxIndex2 = i;
			}
		}
		
		int leftIndex = Math.min(maxIndex1, maxIndex2);
		int rightIndex = Math.max(maxIndex1, maxIndex2);
		if(leftIndex < rightIndex){
			ans += getPartWater(leftIndex, rightIndex, height);
		}
		if(leftIndex > left){
			ans += getAns(height, left, leftIndex);
		}
		if(rightIndex < right){
			ans += getAns(height, rightIndex, right);
		}
		return ans;
	}
	
	public int trap(int[] height) 
	{
		return getAns(height, 0, height.length-1);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值