Word Search II
A hard Backtracking problem included in Love Babbar 450, Striver A2Z. Below: the roles whose interviews prioritise this topic, and how to practise it.
- Topic
- Backtracking
- Sheets
- 2
- Core for
- 0 roles
- Platform
- LeetCode
The problem
Given an m×n board of characters and a list of words, find all words that can be constructed by sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same cell may not be used more than once in a single word.
Example 1
- Input
- board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"]
- Output
- ["eat","oath"]
- Why
- "eat" can be formed starting at (1,0)->(1,1)->(1,2). "oath" can be formed starting at (0,0)->(0,1)->(1,1)->(2,1). "pea" and "rain" cannot be formed on the board.
Example 2
- Input
- board = [["a","b"],["c","d"]], words = ["abcb"]
- Output
- []
- Why
- "abcb" cannot be formed because after visiting (0,0)->(0,1), there is no unvisited adjacent cell containing 'c' to continue the path.
Constraints
- m == board.length
- n == board[i].length
- 1 <= m, n <= 12
- board[i][j] is a lowercase English letter
- 1 <= words.length <= 3 * 10^4
- 1 <= words[i].length <= 10
- words[i] consists of lowercase English letters
How to think about it
Updated 2026-09-09Searching the board separately for each word duplicates traversal of shared prefixes across thousands of words. Inverting the perspective by indexing all words into a prefix Trie allows a single board DFS to advance through the Trie simultaneously, abandoning entire families of words the moment the board's path diverges from the Trie.
Approaches, worst first
Individual word DFS search
time O(W * m * n * 4^L) · space O(L)
For each word in words, scan the board for starting characters and run DFS backtracking. Re-explores identical paths on the board for words sharing prefixes like 'apple', 'application', and 'apply', leading to severe time limit violations with 30,000 words.
Trie-directed board traversal
time O(m * n * 4^L) · space O(TotalCharacters)
Build a Trie of all words. From each board cell, step into the Trie matching board[r][c]. Backtrack in 4 directions, advancing both grid position and Trie node. When a node marks word completion, collect the word and nullify its marker to prevent duplicates.
Trie traversal with leaf pruningWrite this one
time O(m * n * 4^L) · space O(TotalCharacters)
Enhance Trie DFS by pruning leaf nodes after words are found. Once a leaf node's word is recorded, remove that branch from the parent. This ensures subsequent board paths do not waste time traversing dead branches for already-found words.
Where people lose marks · 3
- Adding duplicate entries of the same word when multiple distinct paths on the board form the same word. Clearing node.word to null after recording it guarantees uniqueness.
- Failing to restore board[r][c] from its visited sentinel (such as '#') when backtracking, corrupting the board for neighboring starting cells.
- Retaining exhausted leaves in the Trie, causing later cell traversals to repeat exploration for words that have already been discovered.
The theory behind it
Backtracking — the ground this problem stands on. All Backtracking problems
What Backtracking is
Backtracking is an organized trial-and-error search through a maze of possibilities. You make a tentative choice, move forward to explore where that path leads, and if you hit a dead end or finish finding an answer, you back up and undo that choice. By cleaning up your changes before trying the next option, a single shared board or list is explored thoroughly without needing to clone full copies of your data at every turn.
When to reach for it
Reach for backtracking when a problem asks to generate all possible solutions, like all subsets, permutations, valid parentheses combinations, or word search paths on a board. Signals include puzzles with strict constraint rules, like placing eight non-attacking queens on a chessboard or solving a Sudoku grid. Whenever you must construct combinations step by step and abandon dead-end branches early before wasting time exploring impossible paths, use backtracking.
How the pattern works
Follow a three-step rhythm inside a loop: choose, explore, and unchoose. First, check if the current state satisfies your goal; if so, save a copy of it and return. Next, prune illegal moves immediately using constraint checks so unpromising branches are skipped. For each valid candidate, apply the move to your shared path or board, call the recursive function to explore deeper, and finally undo the move right after the call returns. Undoing restores the shared state so sibling choices start from a clean slate.
What each operation costs
| Operation | Time |
|---|---|
| generate all subsets of n elements | O(2^n) |
| generate all permutations of n elements | O(n!) |
| auxiliary recursion stack memory depth | O(n) |
What usually goes wrong with Backtracking
- Adding a mutable path list directly to the final answers collection without creating a shallow copy, leaving every saved result empty once backtracking finishes.
- Forgetting to undo a state change after the recursive call returns, contaminating subsequent branches with leftover moves from earlier paths.
- Generating duplicate subsets or permutations by failing to sort the input array and skip adjacent identical elements during branch selection.
Track this in your role's order
Pick your target role and all 370 problems — including this one — resequence to what that interview actually asks. Free.
Start freeMore Backtracking problems
Problem set and role mapping as of .