バックトラックで 文字の 盤の 上を たどって 言葉が 作れるか調べる
英字が
海外で定番の問題リスト 4 本には入っていません
問題
言葉探しのgrid でgrid[r] は r 行目のword を、true、false を
- どの
マスから 始めてもかまいません - 次の
字へは、 上下左右の どれかで 隣り合う マスへ 進みます。 斜めには 進めません - 1 つの
言葉の 中で、 同じ マスを 2 回使う ことは できません - 行の
数と 列の 数は どちらも 1 以上 6 以下で、 どの 行も 同じ 長さです。 wordの長さは 1 以上 15 以下で、 英大文字だけです
入力と出力の例
例 1
左上の C から
例 2
CODE までは
例 3
右上の T から
面接での聞かれ方
面接では、
- 「文字の 2 次元の
盤と 単語が あります。 隣り合う マスを たどって 単語を 作れるか返してください」 - 書き終えると
「同じ マスを 使わないように、 どう 印を 付けましたか? 戻る ときに 何を しますか?」と 聞かれます - 「単語が
たくさん あったら?」と、 トライ木と 組み合わせる 版へ 広げて 聞かれる ことがあります
斜めに
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「再帰と木」に、
関わる学び
再帰は、
まず 考える手順
段 1
言葉の 1 字目とtrue です。
段 2
ある
段 3
同じ
段 4
どこかのtrue をor と JavaScript の || は、
解答
Python
Python
def word_search(grid, word):
h = len(grid)
w = len(grid[0])
used = set()
def dfs(r, c, k):
if k == len(word):
return True
if not (0 <= r < h and
0 <= c < w):
return False
if (r, c) in used:
return False
ch = grid[r][c]
if ch != word[k]:
return False
used.add((r, c))
k += 1
found = (
dfs(r + 1, c, k) or
dfs(r - 1, c, k) or
dfs(r, c + 1, k) or
dfs(r, c - 1, k))
used.remove((r, c))
return found
for r in range(h):
for c in range(w):
if dfs(r, c, 0):
return True
return FalseJavaScript
JavaScript
function wordSearch(
grid, word
) {
const h = grid.length;
const w = grid[0].length;
const used = grid.map(
() => Array(w).fill(false));
const dfs = (r, c, k) => {
if (k === word.length) {
return true;
}
if (r < 0 || r >= h ||
c < 0 || c >= w) {
return false;
}
if (used[r][c] ||
grid[r][c] !== word[k]) {
return false;
}
used[r][c] = true;
k++;
const found =
dfs(r + 1, c, k) ||
dfs(r - 1, c, k) ||
dfs(r, c + 1, k) ||
dfs(r, c - 1, k);
used[r][c] = false;
return found;
};
return grid.some((row, r) =>
[...row].some((_, c) =>
dfs(r, c, 0)));
}Go
Go
func wordSearch(
grid []string, word string,
) bool {
h := len(grid)
w := len(grid[0])
used := make([][]bool, h)
for r := range used {
used[r] = make([]bool, w)
}
var dfs func(r, c, k int) bool
dfs = func(r, c, k int) bool {
if k == len(word) {
return true
}
if r < 0 || r >= h ||
c < 0 || c >= w {
return false
}
if used[r][c] ||
grid[r][c] != word[k] {
return false
}
used[r][c] = true
k++
found := dfs(r+1, c, k) ||
dfs(r-1, c, k) ||
dfs(r, c+1, k) ||
dfs(r, c-1, k)
used[r][c] = false
return found
}
for r := 0; r < h; r++ {
for c := 0; c < w; c++ {
if dfs(r, c, 0) {
return true
}
}
}
return false
}印は# などに
計算量
- 時間は O(m × n × 3^L) です。
m と n は 盤の 行と 列の 数、 L は 言葉の 長さです。 始めの マスが m × n 個 あり、 1 歩目の あとは 来た方 へ戻れないので、 進める 向きは 3 つまでです - 使う
記憶は O(m × n + L) です。 印の 入れ物が 盤と 同じ 大きさで、 再帰の 深さが L までです
よく ある間違い
- 戻る
ときに 印を 外さない。 1 つの 道で 使った マスが、 別の 道でも 使えなくなります。 始めの マスを 変えた ときにも 印が 残り、 作れる 言葉を falseにしてしまいます - 盤の
外か どうかより 先に マスの 字を見る。 範囲の 外を 読むと、 Python は 負の 番号で 反対の 端を 読み、 JavaScript は undefined、Go は 止まります。 範囲を 先に 確かめます - 言葉の
最後まで 合ったかを、 字を 比べた あとで 確かめる。 k が 言葉の 長さに 達したら、 その 時点で trueです。順を 逆に すると、 言葉の 最後の 字の マスが 盤の 端に ある ときに 外を 読みに行きます - 斜めにも進む。
決まりに ない 向きへ 進むと、 作れないはずの 言葉を trueにします
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「全部の
マスを 始めとして、 言葉の k 字目以降を 作れるかを 調べる 再帰を 呼びます。 盤の 外、 使った マス、 字が 違う マスなら false です。 合っていれば 印を 付けて 上下左右へ 進み、 戻る ときに 印を 外します。 言葉の 最後まで 合えば true です。 始めは m × n 個、 1 歩ごとに 進める 向きは 3 つまでなので、 時間は O(m × n × 3^L) です。」
書き終えたら、
「例 2 の CODED では、
左上の C から O、 D、 E と 進みます。 次の D は E の 左の 1 マスだけで、 そこは もう 印が 付いています。 E から 上の T も 下の S も D ではないので 戻り、 印を 外しながら 全部戻ります。 ほかの 始めの マスに C は 無いので false です。」