Word Search in Grid Using Backtracking in DSA Rust - Time & Space Complexity
We want to understand how the time needed to find a word in a grid grows as the grid or word size changes.
Specifically, how does the search time increase when the grid or word gets bigger?
Analyze the time complexity of the following code snippet.
fn exist(board: &Vec>, word: &str) -> bool {
fn backtrack(board: &Vec>, word: &[char], i: usize, x: usize, y: usize, visited: &mut Vec>) -> bool {
if i == word.len() { return true; }
if x >= board.len() || y >= board[0].len() || visited[x][y] || board[x][y] != word[i] { return false; }
visited[x][y] = true;
let directions = [(1,0), (-1,0), (0,1), (0,-1)];
for (dx, dy) in directions {
let nx = x as isize + dx;
let ny = y as isize + dy;
if nx >= 0 && ny >= 0 && (nx as usize) < board.len() && (ny as usize) < board[0].len() && backtrack(board, word, i+1, nx as usize, ny as usize, visited) {
return true;
}
}
visited[x][y] = false;
false
}
let word_chars: Vec = word.chars().collect();
let mut visited = vec![vec![false; board[0].len()]; board.len()];
for i in 0..board.len() {
for j in 0..board[0].len() {
if backtrack(board, &word_chars, 0, i, j, &mut visited) {
return true;
}
}
}
false
}
This code tries to find if a word exists in a 2D grid by checking each cell and exploring neighbors recursively.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive backtracking exploring up to 4 directions from each cell.
- How many times: For each cell in the grid (m rows * n columns), it may explore up to 4 neighbors for each character in the word (length k).
As the grid size (m*n) or word length (k) grows, the search explores many paths.
| Input Size (m*n, k) | Approx. Operations |
|---|---|
| 10x10 grid, word length 3 | About 10*10 * 4^3 = 6400 checks |
| 10x10 grid, word length 5 | About 10*10 * 4^5 = 102,400 checks |
| 20x20 grid, word length 5 | About 20*20 * 4^5 = 409,600 checks |
Pattern observation: The operations grow quickly because each character can lead to 4 new paths, causing exponential growth with word length.
Time Complexity: O(m * n * 4^k)
This means the time grows quickly with the word length, as each letter can branch into 4 directions, and we try starting from every cell.
[X] Wrong: "The search only checks each cell once, so it is just O(m*n)."
[OK] Correct: Because the search explores many paths recursively for each character, it can revisit cells in different paths, causing exponential growth with word length.
Understanding this complexity helps you explain how backtracking explores many possibilities and why pruning or early stopping matters.
"What if we limited the search to only horizontal and vertical neighbors, removing diagonal moves? How would the time complexity change?"
Practice
Solution
Step 1: Standard word search
Uses 4-directional movement: up(-1,0), down(+1,0), left(0,-1), right(0,+1).Final Answer:
4-directional: up, down, left, right. -> Option AQuick Check:
Standard = 4 dirs. 8-directional is a variant. [OK]
- Using 8 directions when problem specifies 4
- Only checking right and down
- Not using i32 offsets in Rust for signed arithmetic
Solution
Step 1: Word path constraint
Each cell can be used at most once in a single word path. Without marking, a path could revisit the same cell.Step 2: Visited marking
Mark cell before recursing (visited=true). After returning, unmark (backtrack). This ensures no cell is reused in the current path.Final Answer:
Prevent reusing the same cell within one word path. -> Option BQuick Check:
Mark before recurse, unmark on backtrack. [OK]
- Thinking visited is global (it is path-local)
- Not unmarking after backtrack
- Confusing with BFS visited which is permanent
Solution
Step 1: Three pruning conditions
(1) Out of bounds. (2) Already visited. (3) Character mismatch: grid[r][c] != word[index].Final Answer:
Out of bounds OR visited OR character mismatch. -> Option BQuick Check:
Prune when: out-of-grid || visited || wrong char. Any one = false. [OK]
- Only checking bounds but not character match
- Not checking visited
- Pruning at index threshold instead of character match
Solution
Step 1: What index tracks
index tracks characters matched. When index == word.len(), all matched.Final Answer:
index == word.len() - entire word matched. -> Option BQuick Check:
Base case: index == word.len() = found, return true. [OK]
- Checking index == word.len()-1 (off by one)
- Checking grid boundary instead of word index
- Not returning immediately on success
Solution
Step 1: Starting positions
O(m x n) starting cells.Step 2: Branching
At each of L steps, up to 4 directions: 4^L paths per start.Final Answer:
O(m x n x 4^L) -> Option BQuick Check:
m x n starts x 4^L paths = O(m x n x 4^L). [OK]
- Saying O(m x n x L) ignoring branching factor
- Not knowing 4^L from 4 dirs x L steps
- Confusing with BFS which is O(m x n)
Ready to prove it?
Pass the test and this pattern moves unknown
