11.container-with-most-water.md 4.2 KB
Newer Older
L
luzhipeng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
## 题目地址
https://leetcode.com/problems/container-with-most-water/description/

## 题目描述
```
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.
```
 
![11.container-with-most-water-question](../assets/problems/11.container-with-most-water-question.jpg)
```

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
```

## 思路
符合直觉的解法是,我们可以对两两进行求解,计算可以承载的水量。 然后不断更新最大值,最后返回最大值即可。
这种解法,需要两层循环,时间复杂度是O(n^2)

eg:

```js
   // 这个解法比较暴力,效率比较低
    // 时间复杂度是O(n^2)
    let max = 0;
    for(let i = 0; i < height.length; i++) {
        for(let j = i + 1; j < height.length; j++) {
            const currentArea = Math.abs(i - j) * Math.min(height[i], height[j]);
            if (currentArea > max) {
                max = currentArea;
            }
        }
    }
    return max;

```

> 这种符合直觉的解法有点像冒泡排序, 大家可以稍微类比一下

那么有没有更加优的解法呢?我们来换个角度来思考这个问题,上述的解法是通过两两组合,这无疑是完备的,
那我门是否可以先计算长度为n的面积,然后计算长度为n-1的面积,... 计算长度为1的面积。 这样去不断更新最大值呢?
很显然这种解法也是完备的,但是似乎时间复杂度还是O(n ^ 2), 不要着急。

考虑一下,如果我们计算n-1长度的面积的时候,是直接直接排除一半的结果的。

如图:

![11.container-with-most-water](../assets/problems/11.container-with-most-water.png)


比如我们计算n面积的时候,假如左侧的线段高度比右侧的高度低,那么我们通过左移右指针来将长度缩短为n-1的做法是没有意义的,
因为`新的形成的面积变成了(n-1) * heightOfLeft 这个面积一定比刚才的长度为n的面积nn * heightOfLeft 小`

也就是说最大面积`一定是当前的面积或者通过移动短的线段得到`
## 关键点解析

- 双指针优化时间复杂度


## 代码

```js
/*
 * @lc app=leetcode id=11 lang=javascript
 *
 * [11] Container With Most Water
 *
 * https://leetcode.com/problems/container-with-most-water/description/
 *
 * algorithms
 * Medium (42.86%)
 * Total Accepted:    344.3K
 * Total Submissions: 790.1K
 * Testcase Example:  '[1,8,6,2,5,4,8,3,7]'
 *
 * 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
 * 
 */
/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    if (!height || height.length <= 1) return 0;
    
    // 双指针来进行优化
    // 时间复杂度是O(n)
    let leftPos = 0;
    let rightPos = height.length - 1;
    let max = 0;
    while(leftPos < rightPos) {
        
        const currentArea = Math.abs(leftPos - rightPos) * Math.min(height[leftPos] , height[rightPos]);
        if (currentArea > max) {
            max = currentArea;
        }
        // 更新小的
        if (height[leftPos] < height[rightPos]) {
            leftPos++;
        } else { // 如果相等就随便了
            rightPos--;
        }
    }

    return max;
};
```