【Leetcode】11. Container With Most Water (medium)

时间:2021-12-06 10:57:50

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.

【Leetcode】11. Container With Most Water (medium)

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;
}