传送门:11. 盛最多水的容器 - 力扣(LeetCode)
题目
给定一个长度为 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.length2 <= n <= 1050 <= height[i] <= 104
解题思路
可以采用双指针贪心策略求解“盛最多水的容器”问题,具体思路如下:
-
初始化双指针:左指针
l从数组起始位置(0)开始,右指针r从数组末尾位置(height.length - 1)开始,同时初始化最大面积mul为 0。 -
计算当前容器面积:在循环中,通过公式
(r - l) * Math.min(height[l], height[r])计算当前指针所指两块板形成的容器面积,其中r - l是宽度,Math.min(height[l], height[r])是短板高度(决定容器高度)。 -
更新最大面积:使用
Math.max(mul, area)将当前面积与历史最大面积比较,保留较大值。 -
移动指针的贪心策略:若左板高度小于右板(
height[l] < height[r]),右移左指针l++;否则左移右指针r--。这是因为移动短板可能找到更高的板,从而增加面积,而移动长板只会减小宽度且无法增加高度。 -
循环终止条件:当左指针
l大于等于右指针r时,循环结束,返回最大面积mul。
该算法通过单次遍历(时间复杂度 O(n))和常数空间(空间复杂度 O(1))高效求解,体现了贪心算法“局部最优推导全局最优”的思想。
代码
/**
* @param {number[]} height
* @return {number}
*/
var maxArea = function(height) {
// 初始化变量:
// mul: 存储最大面积(初始值为0)
// l: 左指针(从数组起始位置开始)
// r: 右指针(从数组末尾位置开始)
let mul = 0, l = 0, r = height.length - 1;
// 双指针循环条件:左指针小于右指针
while(l < r) {
// 计算当前容器面积:宽度 × 短板高度
// 使用const是因为每次循环的area都是全新变量,且只赋值一次
const area = (r - l) * Math.min(height[l], height[r]);
// 更新最大面积(取当前面积和历史最大面积的较大值)
mul = Math.max(mul, area);
// 贪心策略:移动较短的板以寻找更大面积
if(height[l] < height[r]) {
l++; // 左板较短,右移左指针
} else {
r--; // 右板较短或相等,左移右指针
}
}
// 返回最大面积
return mul;
};
每天一学(小白视角:为什么 area 每次变化还能用 const?)
1. const 的真正含义:「当前作用域内不可重新赋值」
const area = ... 中的 const 限制的是 「在当前作用域内不能给 area 重新赋值」,而不是「值永远不变」。
- 关键:
area是「每次循环创建的新变量」 在代码中,area是在循环内部声明的(比如for循环或while循环)。每次循环都会创建一个 全新的area变量,它们是不同的内存空间,互不干扰。就像你每次考试都会用一张「新的答题卡」,每张答题卡(// 伪代码演示循环中的作用域 while (l < r) { // 第一次循环:创建新变量 area = 计算值1(const声明,当前作用域不可改) const area = (r-l)*Math.min(height[l], height[r]); // 第二次循环:创建新变量 area = 计算值2(又是一个全新的const变量) const area = (r-l)*Math.min(height[l], height[r]); }area)只写一次答案,写完就收走,互不影响。
2. 为什么 const 比 let 更好?
const明确表达「一次性赋值」的意图area的值在每次循环中只计算一次,之后不会再修改(比如不会出现area = area + 1这样的操作)。用const告诉阅读者:「这个变量在当前循环里就是个固定值,放心用,不会变」。let可能隐藏错误风险 如果用let area = ...,虽然语法没错,但可能让人误以为「这个area后面会被修改」。万一不小心写了area = 0这样的代码,const会直接报错提醒你,而let会默默执行,导致难以排查的 bug。
3. 一句话总结
area 虽然「每次循环的值不同」,但「每次都是全新的变量」,且「每个变量只赋值一次」。const 刚好匹配这种场景,既安全又清晰,而 let 反而会模糊代码意图。
(小白友好比喻:const 像一次性水杯,每次用新的,用完即弃;let 像可重复使用的杯子,虽然能用,但这里没必要,还可能被别人误用装别的东西。)