幅優先探索 (BFS) で全部の部屋からいちばん近い出口までの歩数を求める

部屋と出口が並んだ間取りで、どの部屋についても、いちばん近い出口までの歩数を書き込んだ表を返します。全部の出口から同時に広げる幅優先探索で、1 回で全部の歩数を決める練習です。

海外で定番の問題リスト 4 本には入っていません

問題

建物の 1 つの階の間取りを、2 次元の並び grid で受け取ります。各マスは数の 0 (出口) か 1 (部屋) です。上下左右で隣り合うマスへは 1 歩で移れます。マスごとに、いちばん近い出口までの歩数を書いた、同じ形の 2 次元の並びを返す関数を書いてください。出口のマスは 0 です。

  • 出口は少なくとも 1 つあります
  • 斜めには移れません
  • 行の数と列の数は、どちらも 1 以上 100 以下です。どの行も同じ長さです

入力と出力の例

例 1

出口はまん中の 1 つです。四隅の部屋は、出口まで 2 歩です。

grid = [[1, 1, 1], [1, 0, 1], [1, 1, 1]]
[[2, 1, 2], [1, 0, 1], [2, 1, 2]]

例 2

出口が両端にあります。まん中の部屋は、どちらの出口へも 2 歩です。

grid = [[0, 1, 1, 1, 0]]
[[0, 1, 2, 1, 0]]

例 3

出口が左上だけなら、右下の部屋は右へ 2 歩、下へ 2 歩の 4 歩です。

grid = [[0, 1, 1], [1, 1, 1], [1, 1, 1]]
[[0, 1, 2], [1, 2, 3], [2, 3, 4]]

面接での聞かれ方

面接では、短く次のように渡されることが多いです。

  • 「0 と 1 の行列で、各マスからいちばん近い 0 までの距離を返してください」
  • 部屋ごとに出口を探す書き方を出すと、「部屋が 1 万あったら何回探しますか? 逆から探せませんか?」と聞かれます
  • 壁があって通れないマスのある版 (部屋と門の問題) へ広げて聞かれることもあります。壁のマスを列に入れないだけで、同じ書き方で解けます

出口が必ずあるか、斜めに移れるかを最初に確かめておくと、答えの表を埋めきれるかが決まります。

ヒント

まだ開いていません

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

  1. ヒント 2

  2. ヒント 3

  3. ヒント 4答えに近い

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

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

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

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

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

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


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

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