LeetCode 11.盛最多水的容器 (Java)
力扣11. 盛最多水的容器:双指针法详解
一句话点明白你
被官方题解的一位大佬的评论点醒,在这里分享给大家:**我们left++和right–都是为了尝试取到更多的水,如果短的板不动的话,取到的水永远不会比上次多。**你品,你细品!!
题目描述
给定一个长度为 n
的整数数组 height
,表示垂直线的长度。找到两条垂线,使得它们与 x 轴共同构成的容器能容纳最多的水。返回容器的最大储水量。
示例:
- 输入:
height = [1,8,6,2,5,4,8,3,7]
→ 输出:49
- 输入:
height = [1,1]
→ 输出:1
解法思路:双指针法
核心思想
容器储水量由 宽度 和 较短板的高度 共同决定。双指针法从数组两端向中间移动,每次移动较短的边,通过缩小宽度来寻找更高的板,从而探索更大的储水量。
正确性证明
- 贪心策略:移动较短的边可能使高度增加,而移动较长的边只会减少宽度且高度不会超过原短板。
- 数学保证:每次移动后,虽然宽度减小,但保留更长的边有机会找到更高的短板,从而弥补宽度损失。
算法步骤
- 初始化指针:左指针
left = 0
,右指针right = height.length - 1
。 - 循环计算:
- 计算当前容器的储水量:
面积 = min(height[left], height[right]) * (right - left)
。 - 更新最大储水量。
- 移动较短的边的指针(左指针右移或右指针左移)。
- 计算当前容器的储水量:
- 终止条件:当
left == right
时结束循环。
代码实现
public static int maxArea(int[] height) {int left = 0; // 左指针int right = height.length - 1; // 右指针int res = 0; // 最大储水量while (left < right) {// 计算当前容器的储水量int currentRes = Math.min(height[left], height[right]) * (right - left);res = Math.max(res, currentRes);// 移动较短的边的指针if (height[left] < height[right]) {left++;} else {right--;}}return res;
}
力扣通过截图
复杂度分析
- 时间复杂度:O(n),只需一次遍历数组。
- 空间复杂度:O(1),仅使用常量额外空间。
示例解析
以输入 height = [1,8,6,2,5,4,8,3,7]
为例:
步骤 | left | right | 短板高度 | 宽度 | 面积 | 最大面积 | 移动方向 |
---|---|---|---|---|---|---|---|
1 | 0 | 8 | 1 | 8 | 1×8=8 | 8 | 左→右 |
2 | 1 | 8 | 7 | 7 | 7×7=49 | 49 | 右→左 |
3 | 1 | 7 | 3 | 6 | 3×6=18 | 49 | 右→左 |
… | … | … | … | … | … | 49 | … |
最终最大储水量为 49,由左指针 1
(高度 8)和右指针 8
(高度 7)组成的容器获得。
边界情况处理
- 全零数组:所有高度为 0,储水量始终为 0。
- 所有高度相同:储水量由宽度决定,初始宽度最大。
- 单峰/双峰分布:双指针法能正确找到最大容器。
总结
- 双指针法的优势:通过一次遍历高效解决问题,避免暴力法的 O(n²) 复杂度。
- 关键思想:移动较短的边以探索更高的板,确保不漏掉更大储水量的可能性。
相似问题:
- 42. 接雨水
- 15. 三数之和
掌握双指针法的移动策略,能有效解决数组中的区间最优问题!