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

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

海外で定番の問題リスト 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 で全部陸だったらどうなりますか」と、深さの限界を聞かれます
  • 「入力を書き換えてよいですか」「書き換えられないならどうしますか」と、見たマスの印の付け方を聞かれることもあります

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

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

main.py
def count_islands(grid):
    # ここに書きます
    pass


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

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