medium tree, graph, dp questions
This commit is contained in:
124
backend/data/questions/word-search.yaml
Normal file
124
backend/data/questions/word-search.yaml
Normal file
@@ -0,0 +1,124 @@
|
||||
title: Word Search
|
||||
slug: word-search
|
||||
difficulty: medium
|
||||
leetcode_id: 79
|
||||
leetcode_url: https://leetcode.com/problems/word-search/
|
||||
categories:
|
||||
- arrays
|
||||
- recursion
|
||||
patterns:
|
||||
- backtracking
|
||||
- dfs
|
||||
|
||||
description: |
|
||||
Given an m x n grid of characters `board` and a string `word`, return true if `word` exists
|
||||
in the grid.
|
||||
|
||||
The word can be constructed from letters of sequentially adjacent cells, where adjacent cells
|
||||
are horizontally or vertically neighboring. The same letter cell may not be used more than once.
|
||||
|
||||
constraints: |
|
||||
- m == board.length
|
||||
- n == board[i].length
|
||||
- 1 <= m, n <= 6
|
||||
- 1 <= word.length <= 15
|
||||
- board and word consist of only lowercase and uppercase English letters
|
||||
|
||||
examples:
|
||||
- input: 'board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"'
|
||||
output: "true"
|
||||
explanation: "Path exists starting from top-left corner."
|
||||
- input: 'board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"'
|
||||
output: "true"
|
||||
explanation: "Path exists."
|
||||
- input: 'board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"'
|
||||
output: "false"
|
||||
explanation: "Would need to reuse 'B' cell."
|
||||
|
||||
explanation:
|
||||
approach: |
|
||||
1. For each cell, try to start the word from there
|
||||
2. Use DFS with backtracking to explore all paths
|
||||
3. Mark cells as visited during exploration
|
||||
4. Unmark cells when backtracking (restore state)
|
||||
5. If entire word is matched, return true
|
||||
|
||||
intuition: |
|
||||
This is a classic backtracking problem. We explore paths character by character,
|
||||
and if we reach a dead end (no valid next character), we backtrack and try a
|
||||
different direction.
|
||||
|
||||
The key is marking cells as visited during exploration to avoid reusing them,
|
||||
then unmarking when we backtrack to allow other paths to use them.
|
||||
|
||||
common_pitfalls:
|
||||
- title: Not restoring visited state
|
||||
description: |
|
||||
After exploring a path, you must unmark the cell as visited.
|
||||
Otherwise, other paths from earlier cells can't use it.
|
||||
wrong_approach: "Only marking, never unmarking"
|
||||
correct_approach: "Mark before recursion, unmark after"
|
||||
|
||||
- title: Modifying board permanently
|
||||
description: |
|
||||
If you change board[r][c] to mark as visited, restore it after backtracking.
|
||||
|
||||
- title: Checking word completion too late
|
||||
description: |
|
||||
Check if entire word is matched (index == len(word)) at the start of DFS,
|
||||
before any bounds/character checks.
|
||||
|
||||
key_takeaways:
|
||||
- Backtracking = DFS with state restoration
|
||||
- Mark and unmark visited cells around recursive calls
|
||||
- Early termination when full word is found
|
||||
- Grid constraints allow brute force (small board size)
|
||||
|
||||
time_complexity: "O(m × n × 3^L)"
|
||||
space_complexity: "O(L)"
|
||||
complexity_explanation: |
|
||||
Time: Start from each cell, explore up to 3 directions (not the one we came from) for L characters.
|
||||
Space: Recursion depth is at most word length L.
|
||||
|
||||
solutions:
|
||||
- approach_name: DFS with Backtracking (Optimal)
|
||||
is_optimal: true
|
||||
code: |
|
||||
def exist(board: list[list[str]], word: str) -> bool:
|
||||
rows, cols = len(board), len(board[0])
|
||||
|
||||
def dfs(r: int, c: int, i: int) -> bool:
|
||||
if i == len(word):
|
||||
return True
|
||||
|
||||
if r < 0 or r >= rows or c < 0 or c >= cols:
|
||||
return False
|
||||
if board[r][c] != word[i]:
|
||||
return False
|
||||
|
||||
# Mark as visited
|
||||
temp = board[r][c]
|
||||
board[r][c] = '#'
|
||||
|
||||
# Explore all 4 directions
|
||||
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)
|
||||
)
|
||||
|
||||
# Restore (backtrack)
|
||||
board[r][c] = temp
|
||||
|
||||
return found
|
||||
|
||||
for r in range(rows):
|
||||
for c in range(cols):
|
||||
if dfs(r, c, 0):
|
||||
return True
|
||||
|
||||
return False
|
||||
explanation: |
|
||||
Try starting from each cell. Use DFS to match characters one by one.
|
||||
Mark cells temporarily, then restore when backtracking.
|
||||
Reference in New Issue
Block a user