【Hot100 |5-LeetCode 11. 盛最多水的容器】

这段代码是解决 LeetCode 11. 盛最多水的容器 问题的经典双指针贪心解法,核心目标是找到数组中能容纳最多水的 “容器”(由两个柱子和横轴组成的矩形),时间复杂度优化到 O (n),空间复杂度 O (1)。下面从问题理解→核心思路→代码逐行解析→实例演示四个维度详细讲解:

一、问题理解

问题要求

给定一个长度为 n 的整数数组 height,其中 height[i] 表示第 i 根柱子的高度。两根柱子与横轴组成一个 “容器”,容器的容量 = 两根柱子之间的距离(宽度) × 两根柱子中较矮的高度(高度)。要求找出数组中容量最大的容器。

例如:height = [1,8,6,2,5,4,8,3,7],最大容量由索引 1(高度 8)和索引 8(高度 7)组成,宽度为 7(8-1),高度为 7(min (8,7)),容量 = 7×7=49。

二、核心思路:双指针 + 贪心策略

暴力解法(遍历所有可能的两根柱子)的时间复杂度是 O (n²),而双指针法通过贪心缩小范围,实现线性时间复杂度,核心思路:

  1. 双指针初始化:左指针 left 从数组开头(0)出发,右指针 right 从数组末尾(n-1)出发,此时宽度最大(初始潜在容量最大)。
  2. 计算当前容量:容量 = 宽度(right - left) × 高度(min(height[left], height[right]),由矮柱决定)。
  3. 贪心移动指针:为了寻找更大的容量,需要移动指针缩小范围。移动较矮的柱子(因为:若移动较高的柱子,宽度减小,而高度最多还是由矮柱决定,容量必然变小;移动矮柱可能遇到更高的柱子,从而可能增大容量)。
  4. 更新最大容量:每次计算后,用当前容量更新全局最大容量 ans

三、代码逐行解析

java

运行

class Solution {
    public int maxArea(int[] height) {
        // 1. 初始化左指针(数组开头)
        int left = 0;
        // 2. 初始化右指针(数组末尾)
        int right = height.length - 1;
        // 3. 临时存储当前容量
        int total = 0;
        // 4. 存储最大容量(初始为0)
        int ans = 0;
        
        // 5. 双指针循环:当左指针在右指针左侧时,继续缩小范围
        while (left < right) {
            // 6. 计算当前容器的容量:宽度×高度(高度取较矮柱子)
            total = (right - left) * Math.min(height[left], height[right]);
            // 7. 更新最大容量(取当前容量和历史最大的较大值)
            ans = Math.max(total, ans);
            
            // 8. 贪心移动指针:移动较矮的柱子,寻找更大的可能
            if (height[left] < height[right]) {
                left++; // 左柱较矮,左指针右移
            } else {
                right--; // 右柱较矮(或等高),右指针左移
            }
        }
        
        // 9. 返回最大容量
        return ans;
    }
}

四、实例演示(直观理解过程)

以测试用例 height = [1,8,6,2,5,4,8,3,7] 为例,演示双指针移动和容量计算过程:

步骤leftright宽度 (right-left)高度 (min (左,右))当前容量 (total)最大容量 (ans)移动指针(原因)
初始088min(1,7)=18×1=88左柱矮(1<7)→ left=1
1187min(8,7)=77×7=4949右柱矮(7<8)→ right=7
2176min(8,3)=36×3=1849右柱矮(3<8)→ right=6
3165min(8,8)=85×8=4049等高(8=8)→ 右指针左移(right=5)
4154min(8,4)=44×4=1649右柱矮(4<8)→ right=4
5143min(8,5)=53×5=1549右柱矮(5<8)→ right=3
6132min(8,2)=22×2=449右柱矮(2<8)→ right=2
7121min(8,6)=61×6=649右柱矮(6<8)→ right=1
结束11不满足 left<right,循环结束--49-

最终结果ans=49,与预期一致。

五、关键细节与复杂度分析

1. 为什么移动较矮的柱子能找到最大容量?

假设当前左柱高度 < 右柱高度:

  • 若移动右柱(较高的一边),新的宽度减小,且新的高度最多还是左柱高度(因为左柱更矮),因此新容量必然小于当前容量。
  • 若移动左柱(较矮的一边),虽然宽度减小,但可能遇到更高的左柱,新高度可能增大,从而可能得到更大的容量。因此,移动较矮的柱子是 “贪心” 的最优选择,不会错过潜在的更大容量。

2. 当两柱高度相等时,移动哪一侧?

代码中选择移动右指针(else { right--; }),但实际上移动左指针也可以。因为两柱等高时,无论移动哪一侧,新的容量都不可能超过当前容量(宽度减小,高度最多不变),但必须移动才能继续缩小范围,不影响最终结果。

3. 复杂度分析

  • 时间复杂度:O (n)。左右指针从两端向中间移动,每个元素最多被访问一次,总操作次数为 n。
  • 空间复杂度:O (1)。仅使用了leftrighttotalans4 个变量,无额外空间开销。

六、总结

该解法的核心是双指针 + 贪心策略:通过初始最大宽度的容器开始,每次移动较矮的柱子缩小范围,在 O (n) 时间内高效找到最大容量。这种 “从两端向中间收缩,通过局部最优选择逼近全局最优” 的思路,也是解决类似 “区间最值” 问题的经典思想,在面试中高频考察。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值