11. 盛最多水的容器

中等 含交互动画

学完这道你应该能: 说清它为什么用「对撞双指针」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

每个数是一条竖线的高度。选两条线和 x 轴围成容器,求最大盛水面积

height = [1, 8, 6, 2, 5, 7]
输出 = 28 (第 2 条 8 和第 6 条 7,宽 4)

思路解析

枚举所有线对,n² 个组合,n 一大就慢,而且大量组合明显没希望还白算。换个思路:从「最宽」的一对开始,每步只放弃一条注定没希望的线。

l、r 在最左最右,此时宽度最大。面积由矮的那条决定,所以移走矮的——因为留着它、宽度还只会变小,面积只会更差;只有移走它,才可能换到更高的线、把面积翻盘上去。这就是从暴力到双指针的关键转折。

准备 · 两端出发:左指针 l=0、右指针 r=5,从最宽的一对开始。best 先记 0,准备一路刷新。

第 1 次 · 算面积:当前面积 = min(1,7)×5 = 5,刷新 best=5。两条里左边的 1 是矮的,它就是瓶颈。

第 1 次 · 移矮的左:左边 1 比右边 7 矮,移走它(l 右移)。注意不是看面积大小,而是看谁矮就移谁

第 2 次 · 算面积:l 来到 8:面积 = min(8,7)×4 = 28,刷新 best=28!这一步就是最终答案。被丢掉的 1(灰)以后不再看。

第 2 次 · 移矮的右:这回左边 8 高、右边 7 矮,所以移走右边(r 左移)。移矮边的判据每步重新看。

第 3 次 · 面积变小:负例分支:面积 = min(8,5)×3 = 15,比 best 还小,best 不更新。但右边 5 仍是矮的,必须照样移走它——不能因为面积变小就停或回头,宽度只会越来越小,留着矮边没有未来。

第 4 次 · 继续移矮:min(8,2)×2 = 4,更小,best 仍是 28。右边 2 矮,继续 r 左移。

第 5 次 · 相遇收束:最后 min(8,6)×1 = 6。再移一次 l、r 就相遇、循环结束。全程 best 最大是 28,对应一开始那对 8 和 7。

面积受限于矮的一边,留着它宽度还在缩、注定更差;放弃矮的才有翻盘机会——这是对撞双指针里的贪心选择。

参考代码(Python)

Python
1l, r, best = 0, len(height) - 1, 0
2while l < r:
3    area = min(height[l], height[r]) * (r - l)  # 矮边×宽
4    best = max(best, area)               # 刷新最大
5    if height[l] < height[r]: l += 1     # 移走较矮的左
6    else: r -= 1                         # 否则移右
7return best

复杂度分析

  • 时间复杂度:O(n) —— l、r 一头一尾相向,加起来只走一遍 n,不回头
  • 空间复杂度:O(1) —— 只用 l、r、best 几个变量

套路模板

记住骨架:两端收缩、每步移走限制结果的那一端。和「有序找一对」的双指针同形,区别只是「移谁」的判据。

Python
1# 两端向中间收、每步放弃"拖后腿"的一边
2l, r, best = 0, n - 1, 初值
3while l < r:
4    best = 更新(best, 用 l, r 算的值)
5    if 谁是瓶颈 == 左: l += 1
6    else: r -= 1

易错点

  • 错误写法:哪边面积小就移哪边 / 移走较高的一边正确写法:永远移走较矮的一边(判据是「谁矮移谁」,不是「面积大小」。面积由矮边决定,移高边宽度还变小、必更差,会直接错过 28 这种解)
  • 错误写法:面积用较高的高度正确写法:用 min(左, 右) 高度(水从矮的一边溢出,取高边会把面积算大)
  • 错误写法:while l <= r正确写法:while l < r(l == r 时宽度为 0、装不了水,应停下)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →198. 打家劫舍 ← 返回题库