LeetCode 盛最多水的容器:双指针思想一次讲透

1 阅读3分钟

在刷 LeetCode 的过程中,「盛最多水的容器」是一道绕不开的经典题。
它几乎是双指针思想的代表作,不仅出现频率高,而且非常考察对问题本质的理解。

这篇笔记我会围绕一个核心点展开:
为什么双指针是对的?为什么只移动短板?


一、题目回顾

给定一个数组 height,其中:

  • height[i] 表示第 i 根竖线的高度
  • 每两根竖线与 x 轴可以围成一个容器

容器能装水的面积公式是:

area = (right - left) * min(height[left], height[right])

目标很简单:

找到能装水最多的一对竖线,返回最大面积

二、暴力解法为什么行不通?

最直观的想法是:

  • 枚举所有 (i, j)
  • 计算面积
  • 取最大值

代码好写,但时间复杂度是:

O(n²)

当数组规模上来之后,这种解法必然超时。

所以关键问题是:

能不能在不枚举所有组合的情况下,直接逼近最优解?


三、双指针的核心思想

1. 为什么从两端开始?

双指针的起点是:

left = 0
right = n - 1

原因只有一个:

一开始,容器的宽度最大

而面积 = 宽度 × 高度
要想得到最大面积,宽度不能一开始就浪费掉。


2. 当前面积由谁决定?

每一步我们都会计算:

area = (right - left) * min(height[left], height[right])

注意一个关键事实:

面积永远由“较短的那根线”决定

这就是后续指针移动策略的根本依据。


四、为什么只移动短板?

这是这道题的灵魂问题。

假设当前状态是:

height[left] < height[right]

那么:

  • 当前面积被 height[left] 限制
  • 即使右边再高,也没用

如果此时你选择:

移动右指针

  • 宽度变小
  • 高度上限仍然是 height[left]
  • 面积只会变小或不变

移动左指针

  • 宽度变小
  • 但有可能遇到更高的左边竖线
  • 面积才有机会变大

结论只有一个:

哪边短,就移动哪边

这是一个非常典型的贪心策略


五、双指针完整流程

算法流程可以概括为四步:

  1. 左右指针从数组两端出发
  2. 计算当前容器面积,更新最大值
  3. 比较左右高度
  4. 移动较短的那一侧指针

一直重复,直到左右指针相遇。


六、Java 实现代码

这是面试和刷题中最标准、最推荐的写法:

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

        while (left < right) {
            int h = Math.min(height[left], height[right]);
            int area = h * (right - left);
            max = Math.max(max, area);

            if (height[left] < height[right]) {
                left++;
            } else {
                right--;
            }
        }
        return max;
    }
}

七、复杂度分析

时间复杂度:

O(n)

空间复杂度:

O(1)

这也是这道题真正优秀的地方:
用极低的成本完成了对解空间的压缩。


八、这道题真正想考什么?

这道题并不是单纯考你会不会写双指针,而是考:

  • 能不能识别“面积由短板决定”
  • 能不能证明某些情况一定不可能成为最优解
  • 是否具备用指针移动来“剪枝”的能力

如果你能清楚解释一句话:

为什么只移动短的那一边?

那这道题在面试里就已经过关了。


九、总结一句话

盛最多水的容器,本质不是穷举所有可能,
而是通过双指针 + 贪心思想,不断淘汰不可能成为最优解的情况。

这是一道非常值得反复回看的经典题。