本文最后更新于:2020年4月19日 凌晨

地址:https://leetcode-cn.com/problems/container-with-most-water/

题目

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例:

输入:[1,8,6,2,5,4,8,3,7]
输出:49

解题思路

比较典型的双指针问题,这个题难在要把问题读懂,如果能想到是双指针问题,那么这个题已经做好了 80% 了。

双指针问题通用模板:

int i = 0;
int j = nums.size() - 1;
while(i < j){
	do something
	i++;
	j--;
}

我们的目标值只有一个,就是题目要求的最大值。遍历所有可能的情况是很容易写出来的,但却没有必要那么做。

以题目的示例为例,考虑 [1,8,6,2,5,4,8,3,7] 的首尾两个数,我们要找最大值,那么较小的值就可以不再考虑,也就是左侧1小于右侧的7,如果有更大的值,肯定是和较大的数所构成的,第一步我们把左指针右移一位,8和7所能容纳的水量显然大于1和7。

重复上述步骤,根据两端的值移动左右指针,同时不断更新最大值。当遍历结束,题目要求的最大值也就找到了。

代码

class Solution {
public:
    int maxArea(vector<int>& height) {
        //初始化最大值为首尾两条线所围成的容器能容纳的水
        int area = (height.size() - 1) * min(height.front(), height.back());
        int l = 0;
        int r = height.size() - 1;
        while (l < r)
        {
            //去掉较短的一边
            if (height[l] < height[r]) {
                l++;
            }
            else {
                r--;
            }
            //去掉较短一边后首位两条线围成的容器能容纳的水
            int a = (r - l) * min(height[l], height[r]);
            //更新最大值
            area = a > area ? a : area;
        }
        return area;
    }
};