トライ木と深さ優先探索で文字の盤面から言葉を全部探す

文字の盤面の上下左右をたどって作れる言葉を、候補の一覧から全部探して、辞書の順に返します。候補をトライ木にまとめ、盤面を 1 回たどるあいだに全部の候補を同時に調べる練習です。

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

問題

英小文字の盤面 board と、言葉の一覧 words を受け取ります。盤面で作れる言葉を words の中から全部探し、辞書の順 (a から z の順) に並べて返す関数を書いてください。

  • board は文字列の並びで、1 つの文字列が盤面の 1 行です。board[r][c] が r 行 c 列のマスの文字です
  • 言葉は、あるマスから始めて、上下左右に隣り合うマスへ 1 つずつ進み、通ったマスの文字を順に読んで作ります。斜めには進めません
  • 1 つの言葉の中で、同じマスを 2 回使うことはできません
  • words の中に同じ言葉は 2 回出てきません。見つかった言葉は、作り方が何通りあっても 1 回だけ答えに入れます
  • 1 つも作れなければ、空の並び [] を返します
  • 盤面は 1 行以上 12 行以下、1 列以上 12 列以下です。words は 1 個以上 3000 個以下で、どの言葉も 1 字以上 10 字以下の英小文字です

入力と出力の例

例 1

文字の盤面の言葉探しのパズルです。盤面は 3 行 4 列で、上の行から cats、arep、tone と並びます。cat は左上から右へ、tone はいちばん下の行を左から右へ読みます。step は右上の s から左の t、下の e、右の p と曲がって読みます。art は、r の隣に t が無いので作れません。

board = ["cats", "arep", "tone"] words = ["cat", "car", "art", "tone", "pet", "seat", "rot", "step"]
["car", "cat", "pet", "rot", "step", "tone"]

例 2

2 行 3 列の盤面です。god は上の行を右から左へ、dear は d から下の e、右の a、右の r と読みます。read と red は、r の隣に e が無いので作れません。

board = ["dog", "ear"] words = ["god", "dear", "read", "red"]
["dear", "god"]

例 3

aba は、a のマスを 2 回使わないと作れません。

board = ["ab"] words = ["aba", "ab", "b"]
["ab", "b"]

面接での聞かれ方

トライ木とバックトラックを組み合わせる難しい問題として、シニアの面接で出ます。

  • 「盤面から、一覧にある言葉を全部探してください」
  • 言葉を 1 つだけ探す問題 (盤面の単語探し) を解いたあとの続きとして出されることがよくあります。言葉ごとに盤面を探すと、言葉の数だけ時間がかかります
  • 「見つけた言葉の枝をトライ木から外すと、何が速くなりますか?」と、枝を刈る工夫を聞かれることがあります

シニアの問題なので、候補をトライ木にまとめて 1 回のたどりで全部を同時に調べる発想と、戻るときにマスの印を外すバックトラックを、正しく組み合わせられるかが見られます。

ヒント

まだ開いていません

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

  1. ヒント 2

  2. ヒント 3

  3. ヒント 4答えに近い

アルゴリズムのチートシートの「ハッシュマップ」に、この型の要点を表とコードでまとめています。

ハッシュは、値から番地を計算して、探す手間をほぼ 1 回にする仕組みです。重複や回数の問題は、この形で解けます。

main.py
def word_search_grid(board: list[str], words: list[str]) -> list[str]:
    """
    Goal: 何を返すか

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

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

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


# 「実行」を押すと、この行の結果が出ます
print(word_search_grid(["cats", "arep", "tone"], ["cat", "car", "art", "tone", "pet", "seat", "rot", "step"]))

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