盛最多水的容器
难度:
标签:
题目描述
给定一个长度为 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)`?
▷🦆
这种双指针的方法是否总是能找到最优解,还是可能存在某些情况下无法找到最大面积?
▷🦆
在移动指针时,为什么选择移动 `height[i]` 和 `height[j]` 中较小的一个对应的指针,而不是总是移动左指针或右指针?
▷🦆
如果数组 `height` 中存在多个相同的最大高度,这个方法是否仍然有效?
▷🦆
这个算法的空间复杂度是多少,为什么?
▷