题目描述
每个数是一条竖线的高度。选两条线和 x 轴围成容器,求最大盛水面积。
height = [1, 8, 6, 2, 5, 7]
输出 = 24
思路解析
枚举所有线对,n² 个组合。n 一大就慢。换个思路:从「最宽」的一对开始,每步只放弃一条注定没希望的线。
l、r 在最左最右(宽度最大)。面积由矮的那条决定,所以移走矮的——因为留着它、宽度还变小,面积只会更差;移走它才可能遇到更高的线、翻盘。
l=0, r=5:最宽时面积 = min(1,7)×5 = 5。左边的 1 太矮,移走它(l 右移)。
l=1, r=5:现在 min(8,7)×4 = 28,刷新最大值!这次右边 7 较矮,移走它(r 左移)。
l=1, r=4:min(8,5)×3 = 15,没超过 28。右边 5 矮,r 左移。
l=1, r=3:min(8,2)×2 = 4,更小。继续移矮的右边。
l=1, r=2 · 收束:最后 min(8,6)×1 = 6。l、r 即将相遇,全程最大就是 28。
面积受限于矮的一边,所以放弃矮的才有翻盘机会——这是对撞双指针里的贪心选择。
参考代码(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) —— 双指针走一遍
- 空间复杂度:O(1) —— 几个变量
套路模板
记住骨架:两端收缩、每步移走限制结果的那一端。和「有序找一对」的双指针同形,区别只是「移谁」的判据。
Python
1# 两端向中间收、每步放弃"拖后腿"的一边
2l, r, best = 0, n - 1, 初值
3while l < r:
4 best = 更新(best, 用 l, r 算的值)
5 if 谁是瓶颈 == 左: l += 1
6 else: r -= 1易错点
- ❌ 移走较高的一边 → ✅ 移走较矮的一边(面积由矮边决定,移高边宽度还变小、必更差)
- ❌ 面积用较高的高度 → ✅ 用 min(左,右) 高度(水从矮的一边溢出)
以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握。