当然可以用O(n^2)的方法暴力求解,但是题目出来肯定不是让我们暴力求解的。首先想到的是设计一个算法让问题规模不断缩小,这里在求解过程中的变化应该是单向的——比如让底边不断缩短。
我们可以用双指针法,让左右指针向中间移动遍历数组,在这期间每次移动指针底边都缩短1,这时候的问题是,按照什么规则遍历可以保证扫过最大的储水量??在这里,每次向内移动的指针只能是较短边的那一个。
证明:
设容量最大时的状态为s,底边长b,两指针p1、p2指向的边长为l1,l2,容积=min(l1,l2)* b。
如果没有遍历到这种情况,那么一定是其中一个指针p1还没有到达s时p1的位置,另一个指针p2已经越过了s时p2的位置。也就是说,在p2位于s状态的位置,下次循环就要向中间移动的一刻,较短边长为l2,而s状态下参与计算的壁高小于等于l2,同时底边长B大于s状态下的底边长b,容积 = l2 * B,比s状态下更大,s就不是容积最大的状态。
所以,每次迭代,要得到大于等于V0的新容积,向内移动的指针只能是较短边的那一个。
这时候可以写代码了,从两端开始,每次把较短边的指针向内移动一格,维护最大面积maxArea,遍历一次即得出答案。时间复杂度O(n)。
class Solution {
public int maxArea(int [] height) {
int left = 0, right = height.length-1;
int maxArea = 0;
while(left < right) {
int tmp = (right-left)*Math.min(height[left], height[right]);
maxArea = Math.max(maxArea, tmp);
if(height[left] < height[right]) {//不要写成(left<right)
left++;
}else {
right--;
}
}
return maxArea;
}
}