11. 盛最多水的容器

104 阅读2分钟

题目描述

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

示例

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

示例 2:
输入:height = [1,1]
输出:1

示例 3:
输入:height = [4,3,2,1,4]
输出:16

示例 4:
输入:height = [1,2,1]
输出:2

提示:
n = height.length
2 <= n <= 3 * 104
0 <= height[i] <= 3 * 104

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/co…

分析

柱子围成一个矩阵,矩阵的面积与矩阵的长度和宽度有关。
要盛最多的水(矩阵面积最大),尽量要使两点的距离更远,两点对应的高度的较少值更大。
我们定义一个值maxNum表示荣纳水的最大值,双指针left,right分别指向数组的左右两端,
此时,长度为right-left,较小高度为min(height[left], height[right]),面积为
(right-left)*min(height[left], heifht[right]),由于left和right指向数组的两端,
因此right-left的值是最大的,若要下一个矩阵面积大于当前值,right-left的值不可能
比当前更大,因此只能使min(height[left], height[right])更大,所以接下来指针移动时,
要移动当前较少的那个高度值。

例: 高度[1,8,6,2],对应坐标[0,1,2,3]

  1. 初始时left指向值为1,right指向值为2(末尾坐标3的值为2)
  2. 面积max=(right-left)*min(height[right],height[right])=(3-0)*min(1,2)=3
  3. 要想面积max更大,right-left已经没有提升空间,只能寄希望于min(x,y),因此移动值更小的那个指针,这里height[0]=1 < height[3]=2,因此左指针移动
  4. left向右移动1,此时left指向值为8,right指向值为2
  5. max=(3-1)*min(8,2)=4 ...

实现

int maxArea(int* height, int heightSize)
{
    int maxNum = -1;    // 表示可以容纳水的最大值
    int tmpNum = -1;    // 表示当前坐标状态下可以容纳水的最大值
    int left = 0;
    int right = heightSize - 1;      // left, right表示左右指针

    // 初始状态左右指针指向数组两端,每次移动值较小的那个指针,如两个坐标分别为[0,1],[5,3],3比1大,需要把0往后移1
    while (left < right) {
        tmpNum = (right - left) * (height[left] > height[right] ? height[right] : height[left]);
        if (tmpNum > maxNum) {
            maxNum = tmpNum;
        }
        if (height[left] > height[right]) {
            right--;
        } else {
            left++;
        }
    }
    return maxNum;
}