先回忆一下题目:
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.
其实就是在用木桶问题来表述一个数学问题。对于一列非负整数,找出(i,ai)(i,0)(j,aj)(j,0)四个点所能围成的最大矩形的面积。
看到题目,第一反应是两次遍历数组,但时间复杂度是O(N2),过不了大数据集合测试。
那么接下来选择另一种方法,设定两个分别指向数组头部和尾部的pointer( i和j,i<j ),对a[ i ]和a[ j ]进行比较,如果a[ i ] < a[ j ],则右移左指针,否则左移右指针。那么这样做如何能保证遍历出最大矩形呢?
首先,无论是左移右指针还是右移左指针,对于下一次求矩形面积来说,矩形的长是不变的,都是( j-i-1 ),那么只需要比较a[ i ]和a[ j ]、a[ i +1 ]和a[ j ] 以及a[ i ]和a[ j - 1 ]。
这里我们假设a[ i ] > a[ j ],先讨论移动i至i+1的情况,如果a[i+1]>a[i],那么新围成矩形的高为j,长减小1,面积变小,满足条件;如果a[i+1]<a[i],那么新矩形面积最大的情况(a[i+1]>=a[j])也比i和j围成的矩形要小,同样满足条件。再讨论j移动至j-1的情况,如果a[j-1]<a[j],新矩形面积减小,满足条件;如果a[j-1]>a[j],则有可能出现比i和j围成矩形面积更大的举行出现。因此,我们选择在每次比较中,移动数值较小的指针。这样,整个算法趋向于遍历面积更大的矩形。
附上提交代码:
public class Solution {
public int maxArea(int[] height) {
//无论是左指针右移还是右指针左移,差值不变,所以保留较大的,移动较小的。
int start = 0, end = height.length-1;
int max = 0, h=0, area = 0, l = 0;
while(start<end){
l = end-start;
if(height[start]>height[end]){
h = height[end];
end--;
}else{
h = height[start];
start++;
}
area = h * l;
max = max > area ? max : area;
}
return max;
}
}