feat(content): test cases batch 2

This commit is contained in:
2025-05-24 21:00:16 +01:00
parent 2e323d7a06
commit 09ec96a282
10 changed files with 962 additions and 474 deletions

View File

@@ -11,108 +11,160 @@ patterns:
- dfs
description: |
Given an m x n grid of characters `board` and a string `word`, return true if `word` exists
in the grid.
Given an `m × 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.
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
- `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."
explanation: "Path: A(0,0) → B(0,1) → C(0,2) → C(1,2) → E(2,2) → D(2,1)"
- input: 'board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"'
output: "true"
explanation: "Path exists."
explanation: "Path: S(1,3) → E(2,3) → E(2,2)"
- 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: "Would require reusing the 'B' cell at (0,1)."
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.
Imagine walking through a maze of letters, trying to spell out a word. At each step, you can move up, down, left, or right to an adjacent cell. But there's a rule: you can't step on the same cell twice.
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.
This is a classic **backtracking** problem. We try a path, and if it leads to a dead end (wrong character or no valid moves), we **backtrack** — undo our steps and try a different direction.
Think of it like this:
1. Start from any cell that matches the first character
2. From there, try to find the second character in any adjacent cell
3. Mark cells as "visited" to prevent reuse
4. If we hit a dead end, **unmark** the cell and try another path
5. If we match all characters, we've found the word!
The key insight is that backtracking requires **restoring state** after each failed attempt.
approach: |
We solve this using **DFS with Backtracking**:
**Step 1: Try every cell as a starting point**
- Iterate through all cells in the grid
- For each cell, attempt to find the word starting there
&nbsp;
**Step 2: Define the DFS function**
- `dfs(row, col, index)` returns True if we can find `word[index:]` starting from `(row, col)`
- Base case: if `index == len(word)`, we've matched everything — return True
- Boundary check: if out of bounds, return False
- Character check: if `board[row][col] != word[index]`, return False
&nbsp;
**Step 3: Mark, explore, and unmark**
- **Mark**: Temporarily change `board[row][col]` to `'#'` to prevent reuse
- **Explore**: Recursively check all four directions with `index + 1`
- **Unmark**: Restore `board[row][col]` to its original value (backtrack)
&nbsp;
**Step 4: Return result**
- If any DFS call returns True, the word exists
- If all starting points fail, return False
&nbsp;
The unmarking step is crucial — it allows other paths to use the same cell.
common_pitfalls:
- title: Not restoring visited state
- 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"
After exploring a path, you **must** restore the cell's original value. Otherwise, other paths can't use that cell.
- title: Modifying board permanently
description: |
If you change board[r][c] to mark as visited, restore it after backtracking.
```python
# WRONG: Cell stays marked forever
board[r][c] = '#'
result = dfs(...)
return result
- title: Checking word completion too late
# RIGHT: Restore after exploring
board[r][c] = '#'
result = dfs(...)
board[r][c] = original_value # Backtrack!
return result
```
wrong_approach: "Only marking cells, never restoring"
correct_approach: "Store original value, mark, explore, restore"
- 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.
Check if `index == len(word)` **before** bounds and character checks. Otherwise, when we've matched all characters, we might return False due to being "out of bounds" at the next position.
wrong_approach: "Checking bounds/character before word completion"
correct_approach: "if index == len(word): return True # Check first!"
- title: Not Trying All Directions
description: |
You must explore all four directions: up, down, left, right. Missing any direction means missing potential valid paths.
Use short-circuit OR: `dfs(r+1,c) or dfs(r-1,c) or dfs(r,c+1) or dfs(r,c-1)`
wrong_approach: "Only checking some directions"
correct_approach: "Explore all four orthogonal directions"
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)
- "**Backtracking = DFS + state restoration**: Mark before recursion, unmark after"
- "**Early termination**: Return True as soon as the word is found"
- "**In-place marking**: Using `'#'` to mark cells avoids extra space for a visited set"
- "**Small constraints enable brute force**: With m, n ≤ 6 and word ≤ 15, exponential exploration is acceptable"
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.
time_complexity: "O(m × n × 3^L). We try each cell as a start, and from each cell, we explore up to 3 directions (excluding where we came from) for L characters."
space_complexity: "O(L). The recursion stack depth equals the word length L."
solutions:
- approach_name: DFS with Backtracking (Optimal)
- approach_name: DFS with Backtracking
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:
# Base case: found all characters
if i == len(word):
return True
# Boundary check
if r < 0 or r >= rows or c < 0 or c >= cols:
return False
# Character mismatch
if board[r][c] != word[i]:
return False
# Mark as visited
temp = board[r][c]
# Mark cell as visited (temporarily)
original = board[r][c]
board[r][c] = '#'
# Explore all 4 directions
# Explore all four 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)
dfs(r + 1, c, i + 1) or # down
dfs(r - 1, c, i + 1) or # up
dfs(r, c + 1, i + 1) or # right
dfs(r, c - 1, i + 1) # left
)
# Restore (backtrack)
board[r][c] = temp
# Restore cell (backtrack)
board[r][c] = original
return found
# Try every cell as starting point
for r in range(rows):
for c in range(cols):
if dfs(r, c, 0):
@@ -120,5 +172,8 @@ solutions:
return False
explanation: |
Try starting from each cell. Use DFS to match characters one by one.
Mark cells temporarily, then restore when backtracking.
**Time Complexity:** O(m × n × 3^L) — Each starting cell can explore 3 directions per character.
**Space Complexity:** O(L) — Recursion depth equals word length.
We try each cell as a starting point. DFS matches characters one by one, marking cells to prevent reuse. After exploring, we restore the cell's value (backtrack) to allow other paths to use it. Short-circuit OR provides early termination.