DFS + Backtracking による効率的な解法
2次元文字グリッド内で指定された単語が存在するかを判定する問題です。単語は隣接するセル(上下左右)を順次辿って構成され、同じセルは1回しか使用できません。
1 ≤ m, n ≤ 6 (グリッドサイズ)1 ≤ word.length ≤ 15 (単語長)Input: board = [["A","B","C","E"],
["S","F","C","S"],
["A","D","E","E"]],
word = "ABCCED"
Output: true
深さ優先探索(DFS)とバックトラッキングを組み合わせ、各セルを開始点として目標単語と一致するパスを探索します。
from typing import List
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
m, n = len(board), len(board[0])
word_len = len(word)
def dfs(i: int, j: int, k: int) -> bool:
# ベースケース: 単語完成
if k == word_len:
return True
# 境界チェック
if not (0 <= i < m and 0 <= j < n):
return False
# 文字一致チェック
if board[i][j] != word[k]:
return False
# バックトラッキング処理
tmp = board[i][j]
board[i][j] = "#" # 訪問済みマーク
# 4方向探索(短絡評価)
res = (
dfs(i + 1, j, k + 1) or # 下
dfs(i - 1, j, k + 1) or # 上
dfs(i, j + 1, k + 1) or # 右
dfs(i, j - 1, k + 1) # 左
)
# 状態復元
board[i][j] = tmp
return res
# 全セルから開始点を試行
for i in range(m):
for j in range(n):
if dfs(i, j, 0):
return True
return False
# DFS関数の各部分解説
# 1. 成功条件:単語を完全に見つけた
if k == word_len:
return True
# 2. 境界条件:グリッド外アクセス防止
if not (0 <= i < m and 0 <= j < n):
return False
# 3. 一致条件:現在文字が目標文字と一致するか
if board[i][j] != word[k]:
return False
# 4. 状態管理:訪問済みマークと復元
tmp = board[i][j] # 元の値を保存
board[i][j] = "#" # 訪問済みマーク
# ... 探索処理 ...
board[i][j] = tmp # 状態復元(重要!)
探索単語: ABCCED
現在位置: -
探索深度: 0
制約 m, n ≤ 6 かつ word.length ≤ 15 において:
6 × 6 × 4^15 ≈ 3.86 × 10^10 演算# 最適化前:visited配列使用
visited = [[False] * n for _ in range(m)] # O(m×n) 追加メモリ
# 最適化後:インプレース管理
tmp = board[i][j] # O(1) 一時変数のみ
board[i][j] = "#" # 既存配列を活用
# ... 処理 ...
board[i][j] = tmp # 状態復元
# 短絡評価による早期終了
return (dfs(i+1,j,k+1) or dfs(i-1,j,k+1) or
dfs(i,j+1,k+1) or dfs(i,j-1,k+1)) # いずれか成功で即終了