Word Search
Problem Statement
Given an m x n board of characters and a string word, return whether word exists in the grid. The word must be formed by sequentially adjacent cells, where adjacent means horizontally or vertically neighboring. The same board cell may not be used more than once in a single word path.
Input
A character grid board and a target string word.
Output
A boolean: true if some valid path spells the whole word, otherwise false.
Constraints
- •
1 <= m, n <= 6 - •
1 <= word.length <= 15 - •
board and word consist of lowercase and uppercase English letters - •
The same cell cannot be reused within one path
Examples
Example 1
board = [[A,B,C,E],[S,F,C,S],[A,D,E,E]], word = ABCCED
trueExample 2
board = [[A,B,C,E],[S,F,C,S],[A,D,E,E]], word = SEE
trueExample 3
board = [[A,B,C,E],[S,F,C,S],[A,D,E,E]], word = ABCB
falseLearning Objectives
- Recognise grid word search as board backtracking with a moving cell and a word index.
- Mark a cell as visited before exploring neighbors and restore it afterward.
- Prune immediately on bounds, character mismatch, or revisiting the current path.
- Use a returned boolean to stop the search as soon as one complete path is found.
Intuition
Pattern Recognition
This is a board-search backtracking problem: build one path through a grid while obeying local constraints. The state is the current cell and the next index of word to match. The choices are the four neighboring cells. The base case is matching every character.
The place, validate, recurse, undo pattern appears as a visited marker. Once a cell matches word[index], mark that cell so the same path cannot use it again, recurse into four directions for index + 1, then restore the original character before returning. The in-place trick uses a plain placeholder character such as # instead of a separate visited matrix; because the cell is restored, sibling branches see the board exactly as it was.
This is a single-solution search, not an enumeration problem. Returning true from the DFS lets the first completed word path short-circuit all remaining branches.
Common mistakes
- ×Forgetting to restore the marked cell, which corrupts sibling searches from other starting cells.
- ×Allowing diagonal moves even though the problem only permits horizontal and vertical adjacency.
- ×Checking visited after overwriting the cell in a way that loses the original character.
- ×Continuing to explore after the word is already matched instead of returning **true** immediately.
Algorithm Explanation
State
Each DFS frame carries row, col, and index. The board itself stores the current path by temporarily replacing visited cells with #. A frame is valid only when the position is inside the board and board[row][col] equals word[index].
Recursion tree
For word = ABCCED, the search tries each board cell as a possible starting A. From the A at row 0 column 0, the next level branches to up, down, left, and right for B. Three branches are cut by bounds or mismatch, while the right branch reaches B. The same pattern repeats: from B, only the right C survives; from that C, the downward C survives; then E and D complete the word.
Pruning
Cut a branch if the cell is out of bounds, if the board character does not match the current word character, or if the cell is already marked # by the current path. The character mismatch check is the main pruning. The returned boolean also prunes the rest of the search once a full word is found.
Algorithm
- Iterate over every cell as a possible start for word[0].
- In DFS, return true when index == word.length.
- Reject the frame if the cell is outside the board or does not match word[index].
- Save the original character and place the visited marker # in the cell.
- Recurse to the four neighboring cells with index + 1.
- Undo by restoring the saved character before returning.
- If any start returns true, return true; otherwise return false.
Solutions
Solution: In-place DFS with mark and restore
Treat each cell as a possible first character. The DFS validates the current character, places a temporary visited marker, explores four neighbors, and then restores the cell. This keeps auxiliary space to the recursion stack while preserving the board for other starting points.
Step-by-step
- Scan every row and col in the board.
- Call DFS from that cell with index = 0.
- In DFS, finish successfully when index reaches word.length.
- Reject out-of-bounds cells and cells whose character does not equal word[index].
- Save the current character, write # into the board, and recurse up, down, left, and right.
- Restore the saved character before returning the boolean result.
O(m * n * 3^L)
O(L)
There are m * n starts. After the first step, each path has at most 3 useful directions because it should not immediately return to the marked previous cell. L is word.length.
Java implementation
Dry Run
Sample input
board = [[A,B,C,E],[S,F,C,S],[A,D,E,E]], word = ABCCED. Track one successful path and the pruned branches around it.
| step | cell | choice | action (place/undo) | state |
|---|---|---|---|---|
| 1 | (0,0) | match A | place # | path A, index moves to 1 |
| 2 | (0,1) | move right to B | place # | path A -> B |
| 3 | (0,2) | move right to C | place # | path A -> B -> C |
| 4 | (0,3) | try E for next C | prune | mismatch, return to (0,2) |
| 5 | (1,2) | move down to C | place # | path A -> B -> C -> C |
| 6 | (2,2) | move down to E | place # | path A -> B -> C -> C -> E |
| 7 | (2,1) | move left to D | place # | word complete |
| 8 | return stack | found true | undo restore cells | all markers are restored as true propagates |
The placeholder prevents reusing cells already in the path. Even though the search returns true, every active frame restores its cell before unwinding, so the board is left unchanged.
Interview Tips
Lead with the invariant: every active path has unique cells because chosen cells are marked and later restored. Mention both implementation options, in-place # marking or a visited matrix, then prefer in-place marking when mutation is allowed. Also say why the boolean return matters: Word Search asks whether one path exists, so the first full match should stop the recursion.
Likely follow-ups
- How would you return the actual path of coordinates instead of only **true** or **false**?
- How would the solution change if diagonal moves were allowed?
- How would you search for many words on the same board efficiently?
- How would you handle a board where **#** could appear as a normal character?
Similar Problems
Key Takeaways
- Grid search becomes backtracking when a path cannot reuse cells.
- Mark before exploring neighbors and restore before returning to keep sibling branches independent.
- Bounds and character mismatch checks are powerful pruning gates.
- Use a boolean return for existence problems so one found path stops the search.