トライ木で伏せ字の入った言葉を探す仕組みを作る

言葉を​足す操作と、​どの​ 1 文字にも​当たる​伏せ字 . を​含む​言葉を​探す操作を​持つ仕組みを​作る。​トライ木の​上で、​当てはまる節の​集まりを​ 1 文字ず​つ進めて​いきます。

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

問題

言葉をしまっておき、伏せ字を含む形で探せる仕組み WordBook を作ってください。次の 2 つの操作を持ちます。

  • addWord(w) は、言葉 w をしまいます。何も返しません
  • search(w) は、しまった言葉のうち w に当てはまる物が 1 つでもあれば真、無ければ偽を返します。w の中の . は、どの 1 文字にも当たる伏せ字です。長さは同じでなければ当てはまりません

メソッドの名前は、JavaScript は上のまま、Python は add_word と search、Go は AddWord と Search です。Go では newWordBook() で作ります。

  • しまう言葉は英小文字 (a から z) だけ、探す言葉は英小文字と . だけです
  • 長さはどれも 1 以上 25 以下です
  • 探す言葉に入る . は、1 つの言葉につき 2 つまでです
  • 操作は全部で 10000 回以下です

例は、呼ぶ操作の名前の並び ops と、それぞれに渡す引数の並び args で書きます。最初の "WordBook" は作るところです。出力は操作ごとの戻り値の並びで、作るところと addWord は null です。

入力と出力の例

例 1

"r.pe" は "rope" にも "ripe" にも当たります。"rop" は頭が合うだけで、言葉としてはありません。

入力

ops = ["WordBook", "addWord",
  "addWord", "search",
  "search", "search"]
args = [[], ["rope"],
  ["ripe"], ["r.pe"],
  ["rop"], ["..pe"]]

出力

[null, null, null, true,
 false, true]

例 2

伏せ字は 1 文字ちょうどに当たります。長さの違う言葉には当たりません。

入力

ops = ["WordBook", "addWord",
  "addWord", "search",
  "search", "search"]
args = [[], ["go"], ["gold"],
  ["g.."], ["g..d"], ["."]]

出力

[null, null, null, false,
 true, false]

例 3

何もしまっていないうちは、伏せ字だけでも当たりません。

入力

ops = ["WordBook", "search",
  "addWord", "search",
  "search"]
args = [[], ["."], ["a"],
  ["."], ["a"]]

出力

[null, false, null, true,
 true]

面接での聞かれ方

面接では、トライ木の基本を書けるかを確かめたうえで、伏せ字を足して出されることが多いです。

  • 「辞書に言葉を足す操作と、. を伏せ字にして探す操作を作ってください」
  • 書き終えたあとに「伏せ字が多いと、どこまで遅くなりますか?」「言葉を全部並べて比べる書き方と、どちらが速いですか?」と、計算量の見積もりを聞かれます
  • 「* (何文字でも当たる伏せ字) も入れるとしたら、どう変わりますか?」と、形を広げて聞かれることもあります

伏せ字があると、たどる道が 1 本に決まりません。どの節を同時に候補として持つのか、その数がどこまで増えるのかを、書く前に言えることが求められます。

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

main.py
class WordBook:
    def __init__(self):
        # ここに持つ物を書きます
        pass

    def add_word(self, w):
        # ここに書きます
        pass

    def search(self, w):
        # ここに書きます
        pass


# 「実行」を押すと、下の行が動きます
obj = WordBook()
print(obj.add_word("rope"))

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