LeetCode Container With Most Water
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.
翻译过来就是找到两条线,使这两条线和x轴组成的容器能够存放的水最多。
首先想到的方法是采用遍历
1、时间复杂度o(n^2)
对所有可能的情况进行遍历,找出容积最大的情况
int area=0,maxArea=0; int len=height.length; if(len<=1) return 0; for(int i=0;i<len;i++) { for(int j=i+1;j<len;j++) { int min=Math.min(height[i], height[j]); area=min*(j-i); if(area>maxArea) maxArea=area; } } return maxArea;
2、时间复杂度O(n)
这种方法采用两个指示数,分别从左和右向中间靠拢找到最大的面积。
当height[left]<height[right]时,left++;当height[right]<height[left],right--.
现在问题的关键是要证明解法的正确性!
首先为什么要让小的竖线向内移,因为area=(right-left)*min(height[left],height[right]),
设left是小的竖线,此时area'=(right-left)*height[left];
假如让right向内移即right--,设为right',而新的min(height[left],height[right'])<=height[left],同时right'-left<right-left。这样新的area必然会小于之前的area.
为了获取更大的面积,只能让left++,即小的左移。
其次,为什么不让left--呢?即是否存在一个数m,当m<left时,使得面积大于当前最大面积C。
这里会用到数学上的一条性质:a>=min(a,b)。
假设存在这样的一个数m,使得面积大于C,即rearRM=(right-m)*min(height[right],height[m])>C。
由规则所知,从m移动到left,肯定是在right或者right的右边存在一个一个数k,使得height[k]>height[m]。
即之前存在areaKM=(k-m)*min(height[k],height[m])<=C,而areaKM=(k-m)*height[m].
而(k-m)>(right-m),height[m]>=min(height[m],height[right]) ==> areaKM>areaRM ==> C>=areaKM>areaRM>C。
出现矛盾,即不存在这样的m。
同理,在right的右侧是否也存在这样的一个数呢?答案是否定的。
1 public class Solution { 2 public int maxArea(int[] height) { 3 int maxArea=0,area=0; 4 int len=height.length; 5 int left=0,right=len-1; 6 while(left<right) 7 { 8 area=(right-left)*Math.min(height[left], height[right]); 9 if(area>maxArea) 10 maxArea=area; 11 if(height[left]<height[right]) 12 left++; 13 else { 14 right--; 15 } 16 } 17 return maxArea; 18 } 19 }