212. Word Search II
hardAsked at AirbnbGiven an m x n board of letters and a list of words, return all words formed by adjacent cells (no reuse). Airbnb asks this to test trie + DFS — running word-by-word DFS doesn't scale.
By Alex Chen, Founder, InterviewChamp.AI · Last verified
Source citations
Public interview reports confirming this problem appears in Airbnb loops.
- Glassdoor (2026-Q1)— Airbnb senior+ onsite reports include this as a recurring graph+trie hard.
- Blind (2025-11)— Mentioned in Airbnb L5 algorithm-track interviews.
Problem
Given an m x n board of characters and a list of strings words, return all words on the board. Each word must 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 in a word.
Constraints
m == board.lengthn == board[i].length1 <= m, n <= 12board[i][j] is a lowercase English letter.1 <= words.length <= 3 * 10^41 <= words[i].length <= 10All the strings of words are unique.
Examples
Example 1
board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"]["eat","oath"]Example 2
board = [["a","b"],["c","d"]], words = ["abcb"][]Approaches
1. Per-word DFS (LC 79 repeated)
Run Word Search I backtracking once per word from every cell.
- Time
- O(W * m * n * 4^L)
- Space
- O(L)
function findWordsNaive(board, words) {
const m = board.length, n = board[0].length;
function dfs(i, j, w, k) {
if (k === w.length) return true;
if (i < 0 || j < 0 || i >= m || j >= n || board[i][j] !== w[k]) return false;
const tmp = board[i][j];
board[i][j] = '#';
const found = dfs(i + 1, j, w, k + 1) || dfs(i - 1, j, w, k + 1) || dfs(i, j + 1, w, k + 1) || dfs(i, j - 1, w, k + 1);
board[i][j] = tmp;
return found;
}
const result = [];
for (const w of words) {
let ok = false;
for (let i = 0; i < m && !ok; i++) for (let j = 0; j < n && !ok; j++) if (dfs(i, j, w, 0)) ok = true;
if (ok) result.push(w);
}
return result;
}Tradeoff: Repeats identical DFS work across words with shared prefixes. With 3 * 10^4 words this times out. Mention as a stepping stone, then pivot.
2. Trie + backtracking (optimal)
Build a trie of all words. DFS the board, descending the trie in lockstep. Record a word when you hit a node with one stored. Prune empty branches.
- Time
- O(m * n * 4^L)
- Space
- O(total chars)
function findWords(board, words) {
const root = {};
for (const w of words) {
let node = root;
for (const c of w) {
if (!node[c]) node[c] = {};
node = node[c];
}
node.word = w;
}
const m = board.length, n = board[0].length;
const result = [];
function dfs(i, j, parent) {
const c = board[i][j];
const node = parent[c];
if (!node) return;
if (node.word) {
result.push(node.word);
node.word = null;
}
board[i][j] = '#';
if (i + 1 < m && board[i + 1][j] !== '#') dfs(i + 1, j, node);
if (i - 1 >= 0 && board[i - 1][j] !== '#') dfs(i - 1, j, node);
if (j + 1 < n && board[i][j + 1] !== '#') dfs(i, j + 1, node);
if (j - 1 >= 0 && board[i][j - 1] !== '#') dfs(i, j - 1, node);
board[i][j] = c;
if (Object.keys(node).length === 0) delete parent[c];
}
for (let i = 0; i < m; i++) for (let j = 0; j < n; j++) dfs(i, j, root);
return result;
}Tradeoff: Single board traversal walking the trie in lockstep. Pruning dead trie branches makes the average case fast.
Airbnb-specific tips
Airbnb wants you to articulate the per-word DFS is wasteful because words share prefixes — a trie lets you walk the board once and descend the trie in lockstep. State that out loud before reaching for the trie code. Pruning is the bonus: empty nodes can be deleted so future cells don't recurse into dead branches.
Common mistakes
- Forgetting to null the word after finding it (causes duplicate results).
- Not pruning dead trie branches — slower but still correct.
- Mutating the board and forgetting to restore on backtrack.
Follow-up questions
An interviewer at Airbnb may pivot to one of these next:
- What if a single cell could be reused within a word? (Different problem entirely.)
- What if the grid is huge and the word list is small? (Per-word DFS might be faster in practice.)
- Radix-tree compression for long shared prefixes.
Solve it now
Free. No sign-up. Python and JavaScript run instantly in your browser.
FAQ
Why mark cells '#' and restore on backtrack?
Marking prevents re-visiting on this DFS path. Restoring allows a different path to use the cell.
Is pruning necessary?
Not for correctness, but dramatically speeds up the average case by skipping exhausted branches.
Free learning resources
Curated free links for this problem.
Practice these live with InterviewChamp.AI
Drill Word Search II and other Airbnb interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.
Practice these live with InterviewChamp.AI →