盛最多水的容器

223 阅读3分钟

这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

leetcode 盛最多水的容器 给你 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

解题: 因为双重暴力循环的性能问题,我们可以考虑优化一下,减少一层循环,比如双指针。对于数组,可以使用两个指针分别指向数组的两端,然后指针往中间移动来遍历数组。根据题目的描述可得水池容量 = 两个下标位置距离 * 两个下标值中最小的一个,所以我们需要尽可能的找到两个乘数的值都是最大的容量。一开始用两个指针指向数组边界,这个时候下标的距离也就是水池的宽是最大的,但是最宽的水池的容量也不一定是最大的,还得看水池的高度,也就是数组元素的值,所以我们还需要移动指针来找到最大的容量。需要舍弃一点宽度,来换取较高的高度,这个时候就只需移动一个指针就可以了,那么就需要判断移动左右的哪个指针了。我们可以根据元素值大小来判断,就是水池边界的高度,假如我们移动水池比较高的一边往里面移动一下,此时水池的宽度肯定是变小了的,但是这个边界高度可能比未移动的边界高度大或者小,但不管如何比起移动之前的水池容量移动后的容量肯定是不会变大的,因为这个容量都是取决于最矮的高度;那么可以换一个移动的方向试试,往水池比较矮的一边移动,同样这个边界可能移动到一个比未移动之前还要高或者矮的地方,如果是比之前未移动前还矮的,那么移动后的容量是变小了的,但是如果移动边界后的高度比未移动之前高,甚至比另外一边的高度都要高,那么这个水池容量是有可能变大了的。因此通过对比可以发现,如果是往水池高的一边移动,那么移动后的水池永远都不会大于移动前的水池容量,但是如果往水池矮的一边移动,那么移动后的水池容量就有可能大于移动前的水池容量。因为我们需要找到水池容量最大的,所以我们每次遍历只能往边界小的一边移动,最终就可以找到最大容量的水池。

public int maxArea(int[] height) {
    int maxWater = 0;

    // 左指针 开始指向数组最左边
    int left = 0;
    // 右指针 开始指向数组最右边
    int right = height.length - 1;
    int minHeight;
    while (left < right) {
        // 获取当前两个位置的最小高度 顺便往高度小的一边移动一下指针
        minHeight = height[left] < height[right] ? height[left++] : height[right--];
        // 保存好水池最大容量 +1因为前面移动了一格
        maxWater = Math.max(maxWater, (right - left + 1) * minHeight);
    }
    return maxWater;
}