Day4:LeeCode Hot4-盛最多水的容器
大家好,继续更新 LeetCode Hot100 刷题精讲系列,今天这道题是 Hot100 里非常经典的双指针题型:盛最多水的容器。
很多人初次看到这道题,第一反应是暴力枚举,但是暴力解法会超时。而双指针解法,只用一次遍历就可以解决。这道题的难点不在于代码,而在于理解双指针为什么是正确的,为什么可以舍弃大量无效状态。
本文将讲解两种解法:暴力枚举法、双指针最优解法,包含完整思路、Java 代码等。
一、题目描述
11. 盛最多水的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i])。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂线8(下标1)和垂线7(下标8),容器高度为min(8,7)=7,宽度=8-1=7,面积7*7=49。
核心关键点:
- 容器面积公式:
面积 = 两条垂线之间的距离 × 两条垂线较小的高度 - 容器的容量由矮的那根柱子决定,高柱子再高也无法提升水位
- 目标:遍历所有两根柱子组合,求最大面积
二、解法一:暴力枚举法
2.1 解题思路
直接枚举所有两根柱子的组合,i 为左柱子下标,j 为右柱子下标(j>i),计算每一组的面积,记录全局最大值。
- 两层循环:外层固定左柱子
i,内层遍历所有右侧柱子j - 每次计算面积:
(j-i)*Math.min(height[i], height[j]) - 更新最大面积
2.2 Java 完整代码
public class MaxArea {
public int maxArea(int[] height) {
int maxArea = 0;
// 左边界
for(int i = 0; i < height.length; i++){
// 右边界,j必须大于i
for(int j = i + 1; j < height.length; j++){
int curArea = (j - i) * Math.min(height[i], height[j]);
maxArea = Math.max(maxArea, curArea);
}
}
return maxArea;
}
}
2.3 复杂度分析
- 时间复杂度:O (n²),两层循环,枚举全部两两组合。数组长度较大时,直接超时。
- 空间复杂度:O (1),仅常数临时变量,无额外空间。
2.4 优缺点总结
- 优点:思路简单直观,容易想到,不容易理解出错。
- 缺点:时间复杂度太高,数组长度大的时候无法通过 LeetCode 时间限制。
适合用来理解题目,面试不推荐写暴力解法。
三、解法二:双指针法
3.1 解题思路
核心思想:左右两个指针分别放在数组两端,不断向内收缩,每次移动高度更小的指针。
初始:left = 0,right = height.length - 1,此时宽度最大。
面积公式:(right-left) * min(height[left], height[right])
关键原理:
假设左柱子高度 < 右柱子高度。此时,当前左指针能组成的最大容器就是当前这个状态。
如果我们固定左指针,右指针无论向左怎么移动,宽度都会变小,而容器高度最多只能等于左柱子高度。不可能得到更大面积。所以这个左指针可以直接舍弃,left++。
反之,如果右柱子更矮,则移动右指针right--。
循环直到 left >= right,全程只遍历一次数组。
3.2 Java 完整代码
public class MaxArea {
public int maxArea(int[] height) {
int left = 0, right = height.length - 1;
int area = 0;
while(left < right){
area = Math.max(area, (right - left) * Math.min(height[left], height[right]));
if(height[left] < height[right]){
left++;
}else{
right--;
}
}
return area;
}
}
3.3 复杂度分析
- 时间复杂度:O (n),仅一次遍历数组,每个元素最多访问一次。
- 空间复杂度:O (1),只使用两个指针与面积变量,常数空间。
3.4 核心优势
- 时间复杂度线性,大数据量也不会超时
- 代码简洁,面试手写速度快
四、两种解法全方位对比
表格
| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
|---|---|---|---|---|
| 暴力枚举法 | O(n²) | O(1) | 思路简单,容易理解 | 大数据量超时 |
| 双指针法 | O(n) | O(1) | 线性时间,性能最优,空间开销极小 | 需要理解双指针收缩原理,思维门槛更高 |
五、面试高频提问与解答
Q1:双指针为什么是正确的?为什么移动矮的柱子?
答:容器的容量由矮柱子决定。假设
height[left] < height[right],当前宽度最大。如果继续保留 left,无论 right 向左移动到哪里,宽度都会变小,容器高度最多等于 height [left],面积一定不会比当前更大。所以 left 这个位置已经没有潜力,直接舍弃,left++。反之移动 right。
Q2:会不会漏掉最优解?
答:不会。双指针每次舍弃的是一定无法构成更大面积的位置,所有有潜力成为最大值的组合都被保留,不会跳过最优答案。
Q3:如果两个柱子高度相等,移动哪一个?
答:height [left] == height [right] 时,移动 left 或者 right 都可以。因为此时两个柱子作为边界,向内移动无论移动哪边,宽度都会减小,新容器的高度一定小于等于当前高度,不可能产生更大面积。
六、刷题总结
盛最多水的容器是双指针经典入门题,这道题重点考察算法优化思维,不仅仅是写代码。面试写出来代码只是基础,必须能讲清楚双指针收缩的原理,证明为什么不会漏掉最优解。
刷题小技巧:遇到数组、区间、求最值的题目,可以优先思考是否可以使用双指针。
下一篇继续更新 LeetCode Hot100 系列,我们将讲解下一道经典题目,持续更新算法面试干货,欢迎持续关注!
浙公网安备 33010602011771号