Container With Most Water问题

Container With Most Water问题

1.问题描述

Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
题目翻译:
对于n个非负整数a1,a2,a3,...,an,每个数字代表一个坐标(i,ai),利用这个坐标向x轴做垂线,利用这样的任意两个垂线和x轴,可以构成一个容器,求体积最大的容器。

2.解题思路

看到这道题的时候,第一思路还是暴力解法,两层循环就能解决问题。果然第一想法都很直观,那么算法的意义就是体现在更好、更快捷的解决问题。这道题的解题思路是利用两个变量分别指向数组的两端,然后这两个变量向中间搜索,每移动一次就算一个数值和当前已经保存的结果进行比较,当两个变量相遇的时候,就能得到最大的容器的体积,这个容器的体积是由长度较短的垂线和这两个变量之间的差值确定的。那么问题来了,怎么保证已经保存的结果是当前最大的,从而最后获得数值是我们所求的最大值?
下面证明一下这个问题:
对于给定的a1,a2,a3,...,an作为输入,我们假设a10和a20是取得最大体积的情况,那么我们就需要证明左指针能够到达a10的位置,而当左指针到达a10的时候,右指针能够到达a20。 也就是说,核心问题是证明:当左指针在a10处,右指针位于a21时,右指针的下一步必须是a20。
由于我们总是移动数值较小的那个指针,即如果a10> a21,指针能够按照我们希望的方式从a21移动到a20。 为什么a10> a21? 因为如果a21> a10,那么a10和a20的所构成的区域面积一定小于a10和a21的面积。 因为a10和a21的面积至少为[a10] *(21-10),而a10和a20的面积最大为[a10] *(20-10)。 所以这就a10和a20有最大区域的矛盾。 所以,a10必须大于a21,那么下一步a21必须移动到a20,必须达到最大值。

3.代码实现

1.初始版本

class Solution {
    public int maxArea(int[] height) {
        
        int len =height.length;
        if(len==0 || height==null){
            return 0;
        }
        int left = 0,right = len-1;
        int max_size = 0;
        while(left < right){
            int lValue = height[left];
            int rValue = height[right];
            max_size = Math.max(max_size,Math.min(lValue,rValue)*(right-left));
            if(lValue>rValue)
                right--;
            else
                left++;
            
        }
        return max_size;
    }
}

2.优化了当遇到更小或相同高度时的情况,减少一定的计算量

class Solution {
    public int maxArea(int[] height) {
        
	        
	        int len =height.length;
	        if(len==0 || height==null){
	            return 0;
	        }
	        int left = 0,right = len-1;
	        int max_size = 0;
	        while(left < right){
	           int l = height[left];
	           int r = height[right];
	        int h = Math.min(l,r);
	        max_size = Math.max(max_size,h*(right-left));
	        while(height[left]<=h&&left<right)
	            left++;
	        while(height[right]<=h&&left<right)
	            right--;    
	        }
	        return max_size;
    }
}
原文地址:https://www.cnblogs.com/chailinbo/p/7515609.html