Backtracking · Grid DFS
m × n grid of letters board and a string word. Return true if the word can be spelled by walking through the grid. Each step moves to a neighbouring cell: up, down, left or right, never diagonally. A cell can be used at most once in a single spelling.
You have a grid of letters, like a word-search puzzle, and a word. Can you spell the word by walking through the grid? You start on any cell, and each step goes to a neighbour: up, down, left or right, never diagonally. You may not use the same cell twice in one spelling.
At every cell we ask one question: does this cell hold the letter I need next? If not, this path is dead right here. If yes, the rest of the word must be found from one of its neighbours. So it is a search where the word length limits the depth, and each step has at most four directions.
The straightforward version gives every step its own copy of the cells used so far, so one path can never affect another.
It is correct. The problem is the copying: every step builds a new set of up to L cells (L is the length of the word), which adds extra work to every one of the many steps. It does not need to be this expensive. Because each path carries its own record, going back to the previous cell needs no clean-up, and that is the reason it works. Can one shared record do the same job?
Keep one record for the whole search, written straight onto the board. When we step onto a cell, we mark it (we overwrite its letter with "#"), so no other step on this path can use it. When we leave the cell, we undo the mark: we put the letter back, so other paths can use that cell again.
This "mark, explore, undo" pattern is called backtracking. The undo line is the important one. The mark must be true only for the cells on the path we are currently exploring.
The search stops as soon as the whole word is matched, and it gives up on a path the moment one letter is wrong. That is what keeps it fast: most paths die within a step or two.
dfs(r, c, 0): can the word be spelled starting here?dfs(r, c, k): k equals the word length⟶every letter matched: return True"#". Try the four neighbours with k + 1.By hand, on the board [["A","C","B"],["D","B","C"]] with the word "CBCA":
Press Play to watch the marks and the undo. In the second example, the word needs three C's but the board has only two, so every path ends in false.
These are the questions that usually come next. Open one to see an answer you could say out loud.
What they are checkingWhether you can see that searching the board once per word repeats work, and know the structure that fixes it. This is the well-known "Word Search II".
A strong answerI would put all the words into a trie, a tree where each path from the top spells the start of some words. Then I run one search over the board, and I walk the trie at the same time. If the letters I have so far are not the start of any word, I stop that path at once. Words that share a start are searched together. When I find a word I can remove it from the trie, so I never report it twice, and so the trie keeps shrinking.
What they are checkingWhether you really understand what the mark means. This is the line a careful interviewer will ask about.
A strong answerThe marks would pile up. After one dead-end path, all its cells would stay as "#", and no later path could use them. So a word that needs one of those cells would be missed, and the function would return false when the answer is true. The mark has to mean "on the path I am on right now", and the undo is what keeps it true.
What they are checkingWhether you think about cheap checks before an expensive search.
A strong answerYes. Before searching, I can count the letters on the board. If the word needs more of some letter than the board has, the answer is false right away. A second idea is to start from the end of the word if its first letter is more common on the board than its last, since fewer starting cells means fewer searches. Both are my own reasoning about cutting work. They do not change the worst case, but they often skip the search entirely.