---
title: Container With Most Water
difficulty: Medium
category: Two Pointers
leetcode_id: 11
revision_count: 1
last_revision: 2026-09-12
---

# Container With Most Water

> **LeetCode:** [#11](https://leetcode.com/problems/container-with-most-water/)
> **Сложность:** Medium
> **Категория:** Two Pointers

## Условие

Дан массив `height` длины `n`. Каждая `height[i]` — высота вертикальной линии в точке `i`. Найти две линии, которые с осью X образуют контейнер с **максимальным количеством воды**.

Площадь = `min(height[i], height[j]) * (j - i)`.

```
Input:  height = [1,8,6,2,5,4,8,3,7]  →  Output: 49
Input:  height = [1,1]                 →  Output: 1
```

## Ключевая идея

Два указателя **с краёв** массива. На каждом шаге двигаем **ту сторону, где высота меньше** — потому что именно меньшая высота ограничивает объём, и единственный способ найти бо́льшую площадь — попробовать другую линию с меньшей стороны.

## Оценка сложности

- **Время:** O(n) — один проход
- **Память:** O(1) — только два указателя и максимум

## Решение (Ruby)

```ruby
# @param {Integer[]} height
# @return {Integer}
def max_area(height)
  l = 0
  r = height.length - 1
  max = 0

  while l < r
    # площадь определяется меньшей высотой
    h = [height[l], height[r]].min
    area = h * (r - l)
    max = area if area > max

    # двигаем меньшую сторону
    if height[l] < height[r]
      l += 1
    else
      r -= 1
    end
  end

  max
end
```

## Разбор на примере

```
height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
          l                          r

Шаг 1:  l=0, r=8,  h=min(1,7)=1,  area=1*8=8,    max=8,    двигаем l (1 < 7)
Шаг 2:  l=1, r=8,  h=min(8,7)=7,  area=7*7=49,   max=49,   двигаем r (8 >= 7)
Шаг 3:  l=1, r=7,  h=min(8,3)=3,  area=3*6=18,   max=49,   двигаем r (8 >= 3)
Шаг 4:  l=1, r=6,  h=min(8,8)=8,  area=8*5=40,   max=49,   двигаем r (8 >= 8)
Шаг 5:  l=1, r=5,  h=min(8,4)=4,  area=4*4=16,   max=49,   двигаем r (8 >= 4)
Шаг 6:  l=1, r=4,  h=min(8,5)=5,  area=5*3=15,   max=49,   двигаем r (8 >= 5)
Шаг 7:  l=1, r=3,  h=min(8,2)=2,  area=2*2=4,    max=49,   двигаем r (8 >= 2)
Шаг 8:  l=1, r=2,  h=min(8,6)=6,  area=6*1=6,    max=49,   двигаем r (8 >= 6)
Шаг 9:  l=1, r=1 — стоп

Итого: max = 49
```

## Edge Cases

- **n = 2** (минимальный): [1,1] → площадь 1. Код работает: l=0, r=1, один шаг.
- **Убывающие высоты**: [5,4,3,2,1] → максимум на первой паре (5*4=20).
- **Возрастающие высоты**: [1,2,3,4,5] → максимум на последней паре (4*4=16).
- **Нулевые высоты**: `0 <= height[i] <= 10^4`, но нуль даёт нулевую площадь — корректно.

## Типичные ошибки

1. ❌ **Двигать обе стороны** — нарушает O(n), проверяет лишние комбинации. Двигаем только одну.
2. ❌ **Двигать бо́льшую сторону** — теряем потенциальные максимумы. Нужно двигать меньшую.
3. ❌ **Off-by-one в условии цикла**: `while l <= r` — бессмысленно при l==r (площадь 0), но не вредно. `while l < r` — правильно.

## Альтернативные подходы

| Подход | Время | Память | Комментарий |
|--------|-------|--------|-------------|
| Brute-force | O(n²) | O(1) | Проверить все пары (i, j) |
| **Two Pointers** | **O(n)** | **O(1)** | **финальное решение** |

Brute-force не подходит при n до 10⁵ — не пройдёт по времени. Two Pointers — единственный оптимальный подход.

## Заметки после повторения

_— Заполняется после каждой тренировки._