Backtracking + matrix DFS with no cell reuse
Given a 2D board and a string word, return True if the word can be formed by adjacent cells (up/down/left/right), without reusing any cell in the same path.
board = [["A","B","C","D"],
["S","A","A","T"],
["A","C","A","E"]]
word = "CAT"
Output: True
board = [["A","B","C","D"],
["S","A","A","T"],
["A","C","A","E"]]
word = "BAT"
Output: False
def dfs(r, c, i):
if i == len(word):
return True
if invalid_state:
return False
mark(r, c)
found = dfs(r+1,c,i+1) or dfs(r-1,c,i+1) or dfs(r,c+1,i+1) or dfs(r,c-1,i+1)
unmark(r, c)
return found
word to matchstate=(0,2,0) need='C' action=mark state=(1,2,1) need='A' action=mark state=(1,3,2) need='T' action=mark state=(1,3,3) action=success
Need to confirm if any path forms a target string/pattern.
Movement is constrained to neighbors (4 or 8 directions).
Visited-state tracking is required for each recursion branch.
ROWS, COLS = len(board), len(board[0])
if i == len(word):
return Trueif r < 0 or c < 0 or r >= ROWS or c >= COLS:
return False
if board[r][c] != word[i] or board[r][c] == '#':
return Falsetemp = board[r][c] board[r][c] = '#' res = dfs(r+1,c,i+1) or dfs(r-1,c,i+1) or dfs(r,c+1,i+1) or dfs(r,c-1,i+1) board[r][c] = temp
for r in range(ROWS):
for c in range(COLS):
if dfs(r, c, 0):
return True
return Falsefrom typing import List
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
ROWS, COLS = len(board), len(board[0])
def dfs(r, c, i):
if i == len(word):
return True
if r < 0 or c < 0 or r >= ROWS or c >= COLS:
return False
if board[r][c] != word[i] or board[r][c] == '#':
return False
temp = board[r][c]
board[r][c] = '#'
res = (dfs(r + 1, c, i + 1) or
dfs(r - 1, c, i + 1) or
dfs(r, c + 1, i + 1) or
dfs(r, c - 1, i + 1))
board[r][c] = temp
return res
for r in range(ROWS):
for c in range(COLS):
if dfs(r, c, 0):
return True
return False
Use visited[r][c] instead of mutating board cells.
visited = [[False] * COLS for _ in range(ROWS)] # mark visited[r][c] = True before recursion # reset to False after recursion
Time: O(m * 4^n) Space: O(ROWS*COLS + n)
Track used cells in a set: path.add((r,c)) and remove on backtrack.
if (r, c) in path:
return False
path.add((r, c))
# recurse
path.remove((r, c))
Time: O(m * 4^n) Space: O(n)
board[r][c] after recursion.i == len(word). That means all characters were matched in order.def exist(board, word):
ROWS, COLS = len(board), len(board[0])
def dfs(r, c, i):
if i == len(word):
return True
if r < 0 or c < 0 or r >= ROWS or c >= COLS:
return False
if board[r][c] != word[i] or board[r][c] == '#':
return False
temp = board[r][c]
board[r][c] = '#'
ok = dfs(r+1,c,i+1) or dfs(r-1,c,i+1) or dfs(r,c+1,i+1) or dfs(r,c-1,i+1)
board[r][c] = temp
return ok
Review this pattern after 1 day, 3 days, 7 days, and 14 days. Re-implement all three visited-state variants each review.