Given a 2-D grid of characters board and a string word, return true if the word is present in the grid, otherwise return false.
For the word to be present it must be possible to form it with a path in the board with horizontally or vertically neighboring cells. The same cell may not be used more than once in a word.
Example 1:
Input:
board = [
["A","B","C","D"],
["S","A","A","T"],
["A","C","A","E"]
],
word = "CAT"
Output: trueExample 2:
Input:
board = [
["A","B","C","D"],
["S","A","A","T"],
["A","C","A","E"]
],
word = "BAT"
Output: falseConstraints:
1 <= board.length, board[i].length <= 51 <= word.length <= 10board and word consists of only lowercase and uppercase English letters.
You should aim for a solution with O(m * (4^n)) time and O(n) space, where m is the number of cells in the given board and n is the size of the given word.
As we can start at any cell on the board, we can explore all paths from that cell. Can you think of an algorithm to do so? Also, you should consider a way to avoid visiting a cell that has already been visited in the current path.
We can use a hash set to avoid revisiting a cell in the current path by inserting the (row, col) of the visiting cell into the hash set and exploring all paths (four directions, as we can move to four neighboring cells) from that cell. Can you think of the base condition for this recursive path? Maybe you should consider the board boundaries, and also, we can extend a path if the character at the cell matches the character in the word.
We can use backtracking, starting from each cell on the board with coordinates (row, col) and index i for the given word. We return false if (row, col) is out of bounds or if board[row][col] != word[i]. When i reaches the end of the word, we return true, indicating a valid path. At each step, we add (row, col) to a hash set to avoid revisiting cells. After exploring the four possible directions, we backtrack and remove (row, col) from the hash set.
Before attempting this problem, you should be comfortable with:
We need to check if the word can be formed by walking up/down/left/right on the grid, using each cell at most once in the same path.
So for every cell, we try to start the word there:
If we ever match all characters, we return true (found the word).
word from that cell.DFS with (row, col, i) where i is the index in word we need to match.DFS:i == len(word), all characters matched → return true.false.(row, col) as visited.i + 1.(row, col) (backtrack).true, answer is true; otherwise false.class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
ROWS, COLS = len(board), len(board[0])
path = set()
def dfs(r, c, i):
if i == len(word):
return True
if (min(r, c) < 0 or
r >= ROWS or c >= COLS or
word[i] != board[r][c] or
(r, c) in path):
return False
path.add((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))
path.remove((r, c))
return res
for r in range(ROWS):
for c in range(COLS):
if dfs(r, c, 0):
return True
return FalseWhere is the number of cells in the and is the length of the .
We try to form the word by walking through adjacent cells (up, down, left, right) in the grid.
Each cell can be used only once in the current path, so we keep a visited matrix to mark cells that are already part of the path.
From every cell, we attempt to match the word starting at index 0.
If at any point the character doesn't match, goes out of bounds, or the cell is already visited, we stop that path.
If all characters are matched successfully, the word exists in the grid and we return true.
visited matrix of the same size as the board.(r, c) in the grid, start a DFS to match the word from index 0.DFS (r, c, i):i == len(word), all characters are matched → return true.false.i + 1.DFS call returns true, return true.false.class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
ROWS, COLS = len(board), len(board[0])
visited = [[False for _ in range(COLS)] for _ in range(ROWS)]
def dfs(r, c, i):
if i == len(word):
return True
if (r < 0 or c < 0 or r >= ROWS or c >= COLS or
word[i] != board[r][c] or visited[r][c]):
return False
visited[r][c] = True
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))
visited[r][c] = False
return res
for r in range(ROWS):
for c in range(COLS):
if dfs(r, c, 0):
return True
return FalseWhere is the number of cells in the and is the length of the .
We want to check if the word can be formed by moving up/down/left/right in the grid, using each cell at most once in a single path.
Instead of keeping a separate visited matrix (extra space), we temporarily mark the current cell as used by replacing its character with a special value (like '#').
This means:
'#', we know this cell is already in our current path → we can't reuse it.So the idea is:
DFS to match the word character by character.ROWS, COLS be grid size.dfs(r, c, i) meaning: "Can we match word[i...] starting from cell (r, c)?"i == len(word), we matched all characters → return true.word[i], or cell is already used ('#') → return false.'#').DFS in 4 directions with i + 1.dfs(r, c, 0) from every cell (r, c). If any returns true, answer is true; otherwise false.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 or
word[i] != board[r][c] or board[r][c] == '#'):
return False
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] = word[i]
return res
for r in range(ROWS):
for c in range(COLS):
if dfs(r, c, 0):
return True
return FalseWhere is the number of cells in the and is the length of the .
When marking a cell as visited by changing its value (e.g., to '#'), forgetting to restore the original character after exploring all neighbors will permanently modify the board. This causes other paths starting from different cells to incorrectly treat valid cells as already visited.
Placing the visited check before the character match check can cause subtle bugs. If a cell is marked visited with a special character like '#', comparing board[r][c] != word[i] will correctly fail. However, if using a separate visited structure, the order of checks matters for correctness and clarity.
Starting DFS from every cell without first checking if board[r][c] == word[0] wastes time exploring paths that cannot possibly match the word. While not incorrect, this optimization significantly improves performance on large boards.