一、问题回顾

在力扣 11. 盛最多水的容器 中,我们面临这样的问题:给定 n 个非负整数 a₁,a₂,...,aₙ,每个数对应坐标平面上的一个点 (i, aᵢ)(此处 i 从 1 开始计数)。每条垂直线 i 的两个端点分别是 (i, 0) 和 (i, aᵢ),要求找出其中两条垂直线,使其与 x 轴共同构成的容器能容纳最多的水。

关键说明:

  • 容器不可倾斜,水量高度由两条线中较矮的那条决定(超过该高度会溢出);
  • 输入数组长度 n ≥ 2,确保至少存在两条垂直线可构成容器;
  • 核心计算公式:容器容量 = 两条线的水平距离 × 两条线的最小高度。

二、解题思路

本题的核心目标是找到 “水平距离尽可能远” 且 “较矮边尽可能高” 的两条线,以此最大化容器容量。我们先分析两种解题思路,突出最优方案的优势:

 双指针法(最优解)

为了优化效率,我们采用 双指针 + 贪心策略,将时间复杂度降至 O(n),核心思路如下:

  1. 初始化指针:左指针 i 从 1 开始(对应数组最左侧的线),右指针 j 从数组长度开始(对应数组最右侧的线);
  2. 计算当前容量:利用公式 (j - i) × min(height[i-1], height[j-1]) 计算当前两条线构成的容量(注意转换为数组的 0-based 索引取值);
  3. 更新最大容量:若当前容量大于已记录的最大值,则更新最大值;
  4. 移动指针(贪心核心):移动较矮边的指针—— 因为移动较矮边,才有可能找到更高的边,从而增大后续容量;若移动较高边,不仅距离缩短,高度还不会增加,容量必然变小;
  5. 循环终止:当两指针相遇时,遍历结束,此时记录的最大值即为最终答案。

三、代码实现

class Solution {
public:
    int maxArea(vector<int>& height) {
        // 初始化双指针:i为左指针(1-based,对应数组索引i-1),j为右指针(1-based,对应数组索引j-1)
        // max用于存储最大容量,初始化为0
        int i = 1, j = height.size(), max = 0;
        
        // 循环条件:左指针小于右指针(两指针未相遇,仍有搜索空间)
        while (i < j) {
            // 计算当前容器容量:
            // (j - i)是两指针的水平距离(因i和j是1-based,差值即实际距离)
            // min(height[i-1], height[j-1])取两条线中较矮的高度(决定水量上限)
            int m = (j - i) * min(height[i - 1], height[j - 1]);
            
            // 若当前容量大于已记录的最大值,更新最大值(用swap交换等价于max = m)
            if (m > max) swap(max, m);
            
            // 贪心移动指针:移动较矮的边,寻找更高的线以可能增大容量
            // 若左线更高,移动右指针(j--);否则移动左指针(i++)
            height[i - 1] > height[j - 1] ? j-- : i++;
        }
        
        // 返回最大容量
        return max;
    }
};

四、代码逐行解析

1. 变量初始化

  • int i=1,j=height.size(),max=0:
    • i=1:左指针初始化为 1,对应数组最左侧的线(后续通过i-1转换为 0-based 索引);
    • j=height.size():右指针初始化为数组长度,对应数组最右侧的线(后续通过j-1转换为 0-based 索引);
    • max=0:用于存储最大容量,初始值为 0。

2. 双指针循环逻辑

  • while(i<j):当左指针小于右指针时,持续循环(两指针未相遇,仍有搜索空间);
  • int m=(j-i)*min(height[i-1],height[j-1]):计算当前容量:
    • j - i:两指针的水平距离(因指针是 1-based,差值直接等于实际距离);
    • min(height[i-1], height[j-1]):取两条线的最小高度(避免水量溢出);
    • m:当前两条线构成的容器容量。

3. 最大容量更新

  • if(m>max)swap(max,m):若当前容量m大于已记录的最大容量max,则通过swap函数交换两者的值,等价于max = m,实现最大值更新。

4. 指针移动规则

  • height[i-1]>height[j-1]?j--:i++:三元表达式实现贪心移动:
    • 若左指针对应的线更高(height[i-1] > height[j-1]),则右指针j--(移动较矮的右指针);
    • 否则,左指针i++(移动较矮的左指针)。

5. 返回结果

  • return max:循环结束后,返回记录的最大容量。

五、复杂度分析

  • 时间复杂度:O(n)。双指针从两端向中间移动,每个元素最多被访问一次,遍历次数与数组长度成正比,效率远超暴力法;
  • 空间复杂度:O(1)。仅使用i、j、max、m四个额外变量,不依赖输入规模,空间开销极小。

六、总结

本题的关键在于理解双指针法的贪心策略:通过移动较矮边的指针,确保每次遍历都向 “可能获得更大容量” 的方向前进,既保证了效率,又能找到最优解。

更多推荐