题目描述

✅ 11. 盛最多水的容器

image-20260928194109487

image-20260928194109488

image-20260928194109489

题意分析

从数组中选择两个不同下标作为容器的左右边界,返回能够容纳的最大水量。两条竖线之间的距离是宽度,较矮竖线的高度是水位上限,因此选择 left、right 时,面积为 (right - left) × min(height[left], height[right])。

只计算选定两条边形成的整体面积,中间的竖线不参与扣减,也不需要逐个位置累加积水。竖线的位置不能改变,所以不能按高度排序;返回面积即可,不需要返回两条边的下标。

解法:双指针移动短板

核心思路

[!blue]

若枚举所有边界对,需要平方时间。双指针从数组两端开始,每次计算当前面积,再排除一个不可能带来更优答案的端点,使剩余搜索范围逐步缩小。

假设 height[left] <= height[right],当前面积的高度就是 height[left]。如果保留 left,把右边界改成区间内任意更靠左的位置,宽度一定变小,高度又不可能超过 height[left],新面积就不可能大于当前面积。

当前组合已经参与最大值比较,因此所有仍以 left 为左边界的剩余组合都可以放弃,直接执行 left++。右端更矮时完全对称,执行 right--;两端等高时,两边都满足这个排除依据,移动任意一端即可,代码选择移动右端。

每次删去的候选都不优于已经记录的面积,所以没有逐对枚举也不会漏掉最大值。移动短板只是保留变得更优的可能,并不保证下一次面积一定增大;需要用 ans 始终保存历史最大值,直到两个指针相遇。

解题步骤

  1. 令 left = 0、right = n - 1,从最大宽度开始。
  2. 在 left < right 时,计算当前面积并更新最大值;必须先计算,再移动指针。
  3. 比较两端高度,移动较矮的一端;相等时任选一端移动。
  4. 指针相遇后返回最大面积。

代码实现

class Solution {
    public int maxArea(int[] height) {
        int left = 0;
        int right = height.length - 1;
        int ans = 0;

        while (left < right) {
            int minHeight = Math.min(height[left], height[right]);

            ans = Math.max(ans, (right - left) * minHeight);

            // 宽度变小后,只有移动短板才可能找到更大面积。
            if (height[left] < height[right]) {
                left++;
            } else {
                right--;
            }
        }

        return ans;
    }
}
func maxArea(height []int) int {
    left := 0
    right := len(height) - 1
    ans := 0

    for left < right {
        h := height[left]
        if height[right] < h {
            h = height[right]
        }
        area := (right - left) * h
        if area > ans {
            ans = area
        }

        // 固定较矮端再缩小宽度不会更优,因此排除短板这一端。
        if height[left] < height[right] {
            left++
        } else {
            right--
        }
    }

    return ans
}

复杂度分析

  • 时间复杂度:$O(n)$。每轮至少有一个指针向内移动,总共至多移动 n - 1 次。
  • 空间复杂度:$O(1)$。

关键点总结

[!green]

  • 固定较矮边时,剩余组合的宽度更小、高度上限不变,所以可以一次排除这些组合。
  • 先记录当前面积,再排除短板;ans 保存所有已检查组合中的最大值。
  • 高度相等也能安全排除一端,无需额外搜索分支。

易错点总结

[!yellow]

  • 移动较高的一端会直接放弃这条高边,但它仍可能与内部更高的边组成更优答案,因此没有安全排除的依据。
  • 宽度是两条线的坐标差 right - left,不是区间内元素个数 right - left + 1。
  • 必须先计算当前面积再移动短板,否则可能漏掉最优边界对;数组只有两条线时也要计算一次。
  • 当前面积并不单调,不能因一次下降就提前结束。

相似题目

题目 难度 关联与区别
42. 接雨水 困难 同样由高度限制蓄水,本题只选两条边并计算容器面积,原题每个位置可被多条柱子围住。
15. 三数之和 中等 同样先证明移动某一端不会丢掉更优解,三数之和依据有序和,本题依据较短边限制。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/55764766
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!