#11 双指针 中等

盛最多水的容器

在 LeetCode 上查看 ↗

🎧 语音讲解

开车或通勤时可听,跟着思路走一遍

速度

📋 题目描述

给定一个长度为 n 的整数数组 height。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

示例 1

输入:height = [1,8,6,2,5,4,8,3,7]
输出:49
垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49(索引 1 和 8 之间,min(8,7)×7=49)。

示例 2

输入:height = [1,1]
输出:1
两条线高度均为 1,宽度为 1,面积为 1。

💭 模拟答题者思考

1. 最直接:枚举所有线对 (i, j),面积 min(height[i], height[j]) × (j-i),双重循环 O(n²),n=10⁵ 会超时。

2. 重复在哪里?固定 l 时从右往左扫 r,和固定 r 从左往右扫 l 本质一样——都在暴力枚举宽度。

3. 双指针:从两端出发,宽度最大;要尝试更大面积只能缩宽度,所以每次必须移动一侧指针。

4. 贪心关键:移动较短的那一侧。较短边是当前容器的「短板」,留着它面积不可能变大(宽度还变小了);移走短板才有机会遇到更高的线。

5. 正确性直觉:若移走较长边,宽度 -1 且高度仍受短板限制,面积一定不比现在大,可以安全丢弃这一侧的所有配对。

🧠 变量语义(先读这三句再编码)

变量类型语义(三句法)
l, rint定义:左右两条候选垂线的下标,当前考虑的容器边界
维护:初始 l=0, r=n-1,每次向内移动较短一侧的指针
更新:当 height[l] <= height[r]l++,否则 r--
ansint定义:遍历过程中见过的最大容器面积
维护:每轮用当前 (l, r) 计算面积并与 ans 取 max
更新ans = max(ans, min(height[l], height[r]) * (r - l))

⌨️ 落码步骤

1. 初始化 l=0, r=n-1, ans=0

2. 当 l < r:计算 area = min(height[l], height[r]) * (r - l),更新 ans

3. 若 height[l] <= height[r]l++;否则 r--

4. 循环结束返回 ans

💻 代码实现

class Solution:
    def maxArea(self, height: List[int]) -> int:
        l, r = 0, len(height) - 1
        ans = 0
        while l < r:
            # 当前容器面积:短板高度 × 宽度
            h = min(height[l], height[r])
            ans = max(ans, h * (r - l))
            # 移动较短一侧,才可能找到更大面积
            if height[l] <= height[r]:
                l += 1
            else:
                r -= 1
        return ans
class Solution {
public:
    int maxArea(vector<int>& height) {
        int l = 0, r = height.size() - 1;
        int ans = 0;
        while (l < r) {
            int h = min(height[l], height[r]);
            ans = max(ans, h * (r - l));
            if (height[l] <= height[r])
                l++;
            else
                r--;
        }
        return ans;
    }
};
// 时间 O(n),空间 O(1)

📈 复杂度分析

时间复杂度 O(n)
空间复杂度 O(1)

⚠️ 常见坑

面积公式是 min(左高, 右高) × 宽度,不是 max 或两高之和。

移动指针时应移较短一侧(相等时移哪边都行,习惯 l++);移较长一侧会漏掉更优解。

循环条件是 l < r 而非 l <= r,至少两条线才能构成容器。

🔍 必测边界 Case

Case 1:最短数组
height = [1, 1] → 1
Case 2:单调递增
height = [1, 2, 3, 4, 5] → 6(首尾 min(1,5)×4=4,但中间 2 和 5 可得 6)
Case 3:含零高度
height = [0, 2, 0] → 0(与 0 高度线构成的容器面积为 0)