leetcode-11 Container With Most Water



问题描述:Given n non-negative integers a1, a2, ..., an, where each represents a pointat coordinate (i, ai). n vertical lines aredrawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find twolines, which together with x-axis forms a container, such that the containercontains the most water.

Note: You may not slant the container.

问题分析:水桶问题,取决于|i – j|* min(a[i] ~ a[j]),a[i]a[j]的最小值乘以距离

                                   

代码:

最优解法:类似于TwoSumhttp://blog.csdn.net/woliuyunyicai/article/details/44222949

直观的解释是:容积即面积,它受长和高的影响,当长度减小时候,高必须增长才有可能提升面积,所以我们从长度最长时开始递减,然后寻找更高的线来更新候补;

故根据贪心算法,应使i之前的数都比a[i]要小,j之后的数都比a[j]要小;

所以我们从两头向中间靠拢,同时更新候选值;在收缩区间的时候优先从  x, y中较小的边开始收缩。

类似于2Sum的思想,两边设一个指针,然后计算area,如果height[i] <= height[j],那么i++,因为在这里height[i]是瓶颈,j往里移只会减少面积,不会再增加area

这是一个贪心的策略,每次取两边围栏最矮的一个推进,希望获取更多的水。

一个不严格的证明:

height[i] <=height[j]时,为什么是i++,而不是j++来获取可能更多的水?

假设j' > j,之所以j'往左移,是因为存在height[i'] > height[j'] (i <= i), 而那时area' = (j' - i') *min(height[i'], height[j'])

因为height[j'] ==min(height[i'], height[j']),所以area' = (j' - i') *height[j']。而i j'构成的面积area = (j' - i) * min(height[i], height[j'])area' >= area,所以j不需要往右移。

代码:


public int maxArea(int[] height) {
		if(height == null || height.length == 0)
		{
			return 0;
		}
		
		int i = 0;
        int j = height.length() - 1;
        
        int ret = 0;
        while(i < j)
        {
            int area = (j - i) * Math.min(height[i], height[j]);
            ret = ret > area ? ret : area;
            
            if (height[i] <= height[j])
                i++;
            else
                j--;
        }
        return ret;
}

原始解法,时间复杂度O(O^3)

public class Solution {
    public int maxArea(int[] height) {
		if(height == null || height.length == 0)
		{
			return 0;
		}
		
		int max = 0;
		for(int j = 1; j < height.length; j++)
		{
			int temp_max = 0;
			for(int i = 0; j + i < height.length; i++)
			{
				int temp = MinValue(height, i , j + i);
				temp_max = temp > temp_max ? temp : temp_max;
			}
			max = (temp_max * j) > max ? (temp_max * j) : max;
		}
		
        return max;
    }
	
	//比较数组i-j的最小值
	private int MinValue(int[] data, int start , int end)
	{
		int min = Integer.MAX_VALUE;
		for(int i = start; i <= end; i++)
		{
			if(min > data[i])
			{
				min = data[i];
			}
		}
		return min;
	}
}

解法二:改进算法二,时间复杂度On^2,空间复杂度O(n)


即使用一个数组,存储上一次循环[i , j -1]的最小值saved_min,此次循环中计算[i,j]最小值,仅需要比较saved_min[i]height[j]比较得出最小值即可;

public class Solution {
    public int maxArea(int[] height) {
		if(height == null || height.length == 0)
		{
			return 0;
		}
		
		int max = 0;
		int[] saved_min = new int[height.length];
		for(int j = 1; j < height.length; j++)
		{
			int temp_max = 0;
			for(int i = 0; j + i < height.length; i++)
			{
				if(j == 1)
				{
					saved_min[i] = MinValue2(height[i],height[i + j]);
				}
				else
				{
					saved_min[i] = MinValue2(saved_min[i],height[i + j]);
				}
				temp_max = saved_min[i] > temp_max ? saved_min[i] : temp_max;
			}
			max = (temp_max * j) > max ? (temp_max * j) : max;
		}
		
        return max;
    }
	
	//比较数组i-j的最小值
	private int MinValue2(int a , int b)
	{
		return a < b ? a : b;
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值