Skip to content

盛最多水的容器

更新: 7/4/2026 字数: 0 字 时长: 0 分钟

题目描述

给定一个长度为 的整数数组 height,其中 height[i] 表示第 i 根垂直线段的高度(线段的两端点为 (i, 0)(i, height[i]))。找出其中的两条线段,使它们与 x 轴共同构成的容器可以容纳最多的水,返回这个最大容水量。

容器不能倾斜。由两条线段 i < j 构成的容器容量为:

即「较矮的那条边的高度」乘以「两条边之间的水平宽度」——因为水会从较矮的一侧溢出。

输入:height = [1, 8, 6, 2, 5, 4, 8, 3, 7] 输出:49(选下标 1(高 8)与下标 8(高 7),面积 = min(8,7) × (8-1) = 7 × 7 = 49

盛水容器:容量 = 较矮的墙 × 宽度

思路拆解

暴力解法:枚举所有两两组合

最直接的想法是枚举每一对线段 (i, j),逐个算出面积并取最大值。思路无脑,一定正确,但需要两层循环,时间是 ,数据量大时会超时。

点击展开暴力解法
js
function maxArea(height) {
  let best = 0
  for (let i = 0; i < height.length; i++) {
    for (let j = i + 1; j < height.length; j++) {
      const area = Math.min(height[i], height[j]) * (j - i)
      best = Math.max(best, area)
    }
  }
  return best
}

最优解法:双指针从两端向内收缩

关键观察:一开始把两条边放在数组最左和最右,此时宽度是最大的。 之后无论怎么移动,宽度只会变小。既然宽度只减不增,想让面积有机会变大,就只能寄希望于「较矮的那条边被换成更高的边」。

于是核心决策来了——每次应该移动较矮的一侧,还是较高的一侧?

核心思路

面积由较矮的边决定。如果移动较高的那条边,短板高度不会上升(顶多不变),而宽度一定变小,面积必然不增——这一步毫无意义。反过来,移动较矮的边,才有机会换来更高的短板,从而弥补宽度的损失。所以每一步都移动较矮的一侧

双指针从两端向内收缩,移动较矮的一侧

为什么这样不会漏掉最优解? 考虑当前较矮的边(设为左边 left)。它与右边任何位置组合,面积都不会超过当前值——因为宽度只会更小、而短板高度最多还是它自己。既然以 left 为短板的所有组合里当前这个已是最大,left 就可以被安全地“淘汰”,指针右移。这样每淘汰一条边就前进一步,最终两指针相遇,全程

下面的交互动画完整演示对样例 [1, 8, 6, 2, 5, 4, 8, 3, 7] 的双指针收缩过程:蓝色水面实时反映当前容量,可单步、自动播放与重置:

双指针 · 盛最多水的容器演示
样例输入:[1, 8, 6, 2, 5, 4, 8, 3, 7]
L
1
0
8
1
6
2
2
3
5
4
4
5
8
6
3
7
R
7
8
left0
right8
当前面积0
最大容量0
初始化:left 指向最左、right 指向最右,宽度最大。面积 = 两指针间宽度 × 较矮的那根柱子高度。
步骤 0 / 17

完整代码

js
/**
 * 盛最多水的容器(双指针)
 * @param {number[]} height 各线段高度
 * @return {number} 最大容水量
 */
function maxArea(height) {
  let left = 0                       // 左指针,起于最左
  let right = height.length - 1      // 右指针,起于最右
  let best = 0

  while (left < right) {
    // 面积 = 较矮的边 × 当前宽度
    const area = Math.min(height[left], height[right]) * (right - left)
    best = Math.max(best, area)
    // 移动较矮的一侧,才有机会让短板变高
    if (height[left] < height[right]) {
      left++
    } else {
      right--
    }
  }
  return best
}

复杂度分析

为数组长度。

解法时间复杂度空间复杂度说明
暴力枚举两两组合, 较大时超时
双指针两指针共向内移动 步,一次遍历

双指针每次至少让 leftright 前进一格,两者相遇即结束,总移动步数为 ,故时间 ,且只用了常数额外空间。

边界与易错点

易错点

  1. 面积取的是较矮的边min(height[left], height[right]),不是较高的,也不是两者之和。
  2. 移动方向不能反:必须移动较矮的一侧。移动较高一侧宽度变小、短板不升,面积必不增,会得到错误答案。
  3. 相等时移哪边都行height[left] === height[right] 时,移动任意一侧都不会漏掉更优解(此时无论保留哪边,另一条边为短板的所有组合都不会更大)。
  4. 循环条件是 left < right:写成 <= 会让同一根线段与自身组合,宽度为 0。
  5. 元素个数少于 2:无法构成容器,结果为 0while 循环自然不执行,返回初始 best = 0)。
  6. 别和「接雨水」混淆:本题只用两条边围水、取较矮边;接雨水是每个位置由左右两侧最高墙共同决定,二者模型不同。

一句话总结

宽度从最大开始只减不增,所以盯着短板走:每一步移动较矮的一侧,一次遍历 即可求出最大容量。