ツーポインタで 並んだ壁の あいだに たまる 雨水の 量を求める
幅 1 の
海外で定番の問題リスト 4 本には入っていません
問題
庭に、heights で
- 左端より
左と、 右端より 右には 壁が 無く、 水は そこから 流れ出ます - 高さ 0 の
所は 地面で、 水が たまれば 地面の 上に たまります heightsの長さは 0 以上 20000 以下で、 値は 0 以上 100000 以下です
入力と出力の例
例 1
左の
例 2
まん中が
例 3
左の 4 より
面接での聞かれ方
面接では、
- 「この
棒の あいだに、 雨水は どれだけたまりますか?」 - 「O(n) の
時間で、 記憶を O(1) に できますか?」と、 段を 踏んで 詰められます - 「両端より
外に 水は 流れますか?」と、 決まりを 自分から 確かめるかも 見られます
難しい
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「配列と文字列」に、
関わる学び
配列と
まず 考える手順
段 1
1 つの
段 2
素直に
段 3
両端に
段 4
左の
解答
Python
Python
def trapped_water(heights):
lo = 0
hi = len(heights) - 1
lmax = 0
rmax = 0
water = 0
while lo < hi:
a = heights[lo]
b = heights[hi]
if a < b:
lmax = max(lmax, a)
water += lmax - a
lo += 1
else:
rmax = max(rmax, b)
water += rmax - b
hi -= 1
return waterJavaScript
JavaScript
function trappedWater(
heights
) {
let lo = 0;
let hi = heights.length - 1;
let lmax = 0;
let rmax = 0;
let water = 0;
while (lo < hi) {
const a = heights[lo];
const b = heights[hi];
if (a < b) {
lmax = Math.max(lmax, a);
water += lmax - a;
lo++;
} else {
rmax = Math.max(rmax, b);
water += rmax - b;
hi--;
}
}
return water;
}Go
Go
func trappedWater(
heights []int,
) int {
lo, hi := 0, len(heights)-1
lmax, rmax := 0, 0
water := 0
for lo < hi {
a := heights[lo]
b := heights[hi]
if a < b {
lmax = max(lmax, a)
water += lmax - a
lo++
} else {
rmax = max(rmax, b)
water += rmax - b
hi--
}
}
return water
}lo と hi がlmax と rmax がhi が -1 から
計算量
- 時間は O(n) です。
2 本の 指は 合わせて n - 1 回動き、 1 回の 手間は一定です - 使う
記憶は O(1) です。 指 2 本と 最大 2 つと 合計だけを持ちます - 段 2 の
所ごとに 左右を なめる 書き方は O(n²)、 左右の 最大を 並びに 作る 書き方は 時間 O(n) で 記憶 O(n) です
よく ある間違い
- 水の
高さを、 左右の 最大の 高い方で決める。 低い方の 壁の 上から 水は こぼれます。 例 3 で 高い方の 4 を 使うと、 右端の 3 より 高く 水を 積んで、 8 より 多く返します - 最大を
更新する 前に 水を足す。 いまの 壁が 最大より 高い とき、 lmax - aが負に なり、 水を 減らしてしまいます。 最大を 先に 更新します - 大きい方の
指を動かす。 低い側の 所は 水の 高さが 決まっていますが、 高い 側の 所は まだ 決まっていません。 動かすのは 低い側です - 両端の
所にも 水を 足そうとする。 端の 外に 壁は 無いので、 端の 所に 水は たまりません。 左右の 最大を 端の 壁から 始めれば、 自然に 0 になります
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「1 つの
所に たまる 水は、 左右それぞれの いちばん高い 壁の 低い方から、 その所の 高さを 引いた量です。 両端に 指を 置き、 左右の 最大を 持ちながら 寄せます。 左の 壁が 右より 低ければ、 右には それ以上の 壁が あると 分かっているので、 左の 所の 水は 左の 最大だけで 決まります。 そこで 左の 水を 足して 左を 進めます。 逆も 同じです。 時間 O(n)、 記憶 O(1) です。」
書き終えたら、
「例 1 で
たどります。 左 3 と 右 4 で 左が 低いので、 左の 最大を 3 に して 水 0、 左を 進めます。 次の 0 も 4 より 低く、 3 から 0 を 引いた 3 を 足します。 2 では 1 を 足し、 次の 0 で 3 を 足します。 指が 出会って、 合計は 7 です。」