leetcode
leetcode 1 ~ 50
盛最多水的容器

盛最多水的容器

难度:

标签:

题目描述

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 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

 

提示:

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104

代码结果

运行时间: 68 ms, 内存: 16.2 MB


/*
题目思路:
在Java Stream中解决这个问题不太直接,但我们可以将高度数组与其索引配对,
然后用Stream和Collectors进行两两比较。由于Stream是单向迭代,
因此我们仍然需要通过传统的双指针方式来遍历。
*/
import java.util.stream.IntStream;
import java.util.stream.Collectors;
import java.util.List;
 
public class Solution {
    public int maxArea(int[] height) {
        List<Integer> indices = IntStream.range(0, height.length).boxed().collect(Collectors.toList());
        int left = 0;
        int right = indices.size() - 1;
        int maxArea = 0;
        while (left < right) {
            int minHeight = Math.min(height[indices.get(left)], height[indices.get(right)]);
            int currentArea = minHeight * (indices.get(right) - indices.get(left));
            maxArea = Math.max(maxArea, currentArea);
            if (height[indices.get(left)] < height[indices.get(right)]) {
                left++;
            } else {
                right--;
            }
        }
        return maxArea;
    }
}

解释

方法:

这个题解使用双指针的思路。初始时左指针 i 指向数组的最左端,右指针 j 指向数组的最右端。在左右指针相遇之前,每次计算以当前左右指针为边界形成的区域的面积,并更新最大面积 res。然后将 height[i] 和 height[j] 中较小的一个对应的指针向内移动一步。这样能保证,对于每个状态,左右指针只会向内移动,直到两个指针相遇,过程中会找到能够容纳最多水的两条线。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在计算面积时使用的是 `min(height[i], height[j]) * (j-i)` 而不是直接使用 `height[i] * (j-i)` 或 `height[j] * (j-i)`?
在计算两个垂直线与 x 轴形成的容器的面积时,水的高度由两边较矮的线决定,因为水会从短的一边溢出。因此,使用 `min(height[i], height[j])` 确保不超过任一边的高度。直接使用 `height[i] * (j-i)` 或 `height[j] * (j-i)` 忽视了短边的限制,可能会估算出不实际的更大面积。
🦆
这种双指针的方法是否总是能找到最优解,还是可能存在某些情况下无法找到最大面积?
双指针方法确实能够找到最大水容纳量的最优解。这个方法的核心是通过比较两指针对应的高度来移动指针,从而逐步排除掉不可能产生最大面积的选项。该方法保证了每次移动都是在尝试寻找一个可能更大的面积,从而涵盖了所有可能的最大面积组合。
🦆
在移动指针时,为什么选择移动 `height[i]` 和 `height[j]` 中较小的一个对应的指针,而不是总是移动左指针或右指针?
选择移动 `height[i]` 和 `height[j]` 中较小的一个对应的指针是为了增加找到更大面积的机会。若移动较高的指针,新形成的容器的高度依然受限于较低的旧边界,且宽度减小,这减少了可能的最大面积。而移动较低的指针有可能找到一个更高的边界,从而有可能增加面积。
🦆
如果数组 `height` 中存在多个相同的最大高度,这个方法是否仍然有效?
是的,这个方法仍然有效。双指针法不受具体高度值的影响,而是通过比较两端的高度来决定移动哪个指针。即便数组中存在多个相同的最大高度,双指针法通过逐步移动指针,仍可以评估所有可能的容器,找到可以储存最多水的情况。
🦆
这个算法的空间复杂度是多少,为什么?
这个算法的空间复杂度是 O(1)。双指针方法只需要常数级的额外空间来存储指针和当前最大面积,它不需要额外的数据结构来存储中间结果或者数组副本。因此,它的空间需求不随输入数据的大小而变化。

相关问题

接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

 

示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

 

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105