11. Container With Most Water (medium)
描述
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.
The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.
Example:
Input: [1,8,6,2,5,4,8,3,7]
Output: 49
分析
这道题目和Trapping Rain Water
(收集雨水)有点类似。一开始拿到题目直接往那道题目上去套了,最后发现最后所求的结果只和边界的高度有关。这道题目如果和收集雨水结合一下还是蛮麻烦的。
由于结果只和边界的高度有关,只需要遍历数组,确定所有的可能由两个边界的组合即可。但是如果傻乎乎地写了双重遍历:
for(int i = 0; i < height.length - 1; i++){
for(int j = i + 1; j < height.length; j++){
//do something
}
}
那么无疑一个O(N^2)的时间复杂度是跑不掉了。当遇到双重遍历的时候,首先要考虑能不能使用夹逼法来取代双重遍历,这道题目就可以使用夹逼法来达到O(N)的时间复杂度。
使用两个变量分别代表左右边界,每次向中间移动左边界或者右边界,这样只需要遍历一次数组。如何判断是移动左边界还是右边界呢?最后的结果是左右边界高度低的一方乘以二者之间的距离,二者之间的距离没法改变,肯定是一直在减小的,那么就要确保左右边界高度较低的一方高度要高,那么每次移动边界的时候,移动高度较低的一方即可。
代码
public int maxArea(int[] height) {
int i = 0, j = height.length - 1, sum = 0;
while(i < j){
sum = Math.max(sum, Math.min(height[i], height[j]) * (j - i));
if(height[i] < height[j]){
i++;
}else{
j--;
}
}
return sum;
}