幅優先探索 (BFS) でグリッドの島を数える

グラフ問題 56

陸と海の地図から、上下左右でつながった陸のかたまりがいくつあるかを数える。まだ見ていない陸を見つけるたびに、そこから広がる陸を待ち行列で全部塗りつぶします。

海外で定番の問題リスト 4 本のうち 4 本に入っています (Blind 75、NeetCode 150、Grind 75、LeetCode Top Interview 150)

問題

地図を表す 2 次元の並び grid を受け取ります。各マスは文字の "1" (陸) か "0" (海) です。上下左右のどれかで隣り合う陸どうしは、同じ島に属します。島がいくつあるかを返す関数を書いてください。

  • 斜めに隣り合うだけの陸は、つながっていないものとします
  • 地図の外側は、すべて海だと考えます
  • 行の数と列の数は、どちらも 1 以上 300 以下です。どの行も同じ長さです
  • 関数の中で grid を書き換えてかまいません

入力と出力の例

例 1

左上の 3 マス、右の端の 2 マス、下の真ん中の 1 マスが、それぞれ島になります。

grid = [["1","1","0","0","1"], ["1","0","0","0","1"], ["0","0","1","0","0"]]
3

例 2

斜めにしか隣り合わない陸は、別々の島です。

grid = [["1","0","1"], ["0","1","0"], ["1","0","1"]]
5

例 3

真ん中に海を囲んでいても、まわりの陸がつながっていれば 1 つの島です。

grid = [["1","1","1"], ["1","0","1"], ["1","1","1"]]
1

面接での聞かれ方

面接では、地図の話としてそのまま渡されることが多いです。

  • 「0 と 1 のグリッドがあります。1 のかたまりはいくつありますか」
  • 書き終えたあとに「再帰で書きましたね。グリッドが 1000 × 1000 で全部陸だったらどうなりますか」と、深さの限界を聞かれます
  • 「入力を書き換えてよいですか」「書き換えられないならどうしますか」と、見たマスの印の付け方を聞かれることもあります

斜めをつながりに数えるか、入力を書き換えてよいかは、問題文で決まっていないことがあります。書き始める前に確かめると、あとで直す手間がありません。

ヒント

まだ開いていません

付箋は 4 枚。下の段ほど答えに近づきます

  1. ヒント 2

  2. ヒント 3

  3. ヒント 4答えに近い

アルゴリズムのチートシートの「グラフ探索と幅優先探索」に、この型の要点を表とコードでまとめています。

グラフ探索は、つながりを近い順か奥からたどります。迷路、最短の手数、講座を受ける順のような問題が同じ形です。

main.py
def count_islands(grid: list[list[str]]) -> int:
    """
    Goal: 何を返すか

    idea1: まず思いつく案
    -> runtime: O(?)  space: O(?)

    idea2: もっと速い案
    -> runtime: O(?)  space: O(?)

    edge case: 空、1 つだけ、など
    """
    # ここに書きます
    pass


# 「実行」を押すと、この行の結果が出ます
print(count_islands([["1", "1", "0", "0", "1"], ["1", "0", "0", "0", "1"], ["0", "0", "1", "0", "0"]]))

できているか「例で確かめる」を押すと、問題の例を全部この関数に渡して、通ったかをここに出します