Backtracking Interview Template and Talk Track
Backtracking interviews are less about clever tricks and more about a stable ritual: choose, explore, unchoose—plus a prune you can say in one sentence. This backtracking interview template talk track gives you that ritual so you do not freeze when the prompt says “return all…” or “place so that…”.
The 10-second classification
Ask:
- Am I building a solution incrementally and discarding dead ends?
- Do I need all valid configurations, or the first / count / optimal one?
- Is the search space permutations, combinations/subsets, or a grid / constraint placement?
- What is the prune—when is the partial solution already illegal?
Talk track:
“I’ll use backtracking: maintain a partial path, try each legal next choice, recurse, then undo. I’ll prune as soon as the partial state breaks a constraint.”
If the problem is optimal over overlapping subproblems with optimal substructure, consider DP instead. Say that fork early when relevant.
Universal skeleton
def backtrack(path, state):
if is_goal(path, state):
record(path)
return
for choice in candidates(path, state):
if not is_valid(choice, path, state):
continue
apply(choice, path, state) # choose
backtrack(path, state) # explore
undo(choice, path, state) # unchoose
Narrate the three verbs every time you write them: choose, explore, unchoose. Interviewers listen for undo discipline.
Pattern A: subsets
def subsets(nums):
out = []
path = []
def dfs(start):
out.append(path.copy())
for i in range(start, len(nums)):
path.append(nums[i])
dfs(i + 1)
path.pop()
dfs(0)
return out
Talk track:
“At each index I either have already decided earlier elements; from
startonward I choose next elements in order so sets aren’t duplicated.”
Pattern B: combinations (size k)
Same as subsets, but only record when len(path) == k, and stop deepening past k.
def combine(n, k):
out, path = [], []
def dfs(start):
if len(path) == k:
out.append(path.copy())
return
for i in range(start, n + 1):
# optional prune: not enough numbers left
need = k - len(path)
if n - i + 1 < need:
break
path.append(i)
dfs(i + 1)
path.pop()
dfs(1)
return out
State the prune: remaining slots vs remaining numbers.
Pattern C: permutations
def permute(nums):
out, path = [], []
used = [False] * len(nums)
def dfs():
if len(path) == len(nums):
out.append(path.copy())
return
for i, x in enumerate(nums):
if used[i]:
continue
used[i] = True
path.append(x)
dfs()
path.pop()
used[i] = False
dfs()
return out
Talk track:
“Every position can take any unused element.
usedmarks choose/unchoose.”
For duplicates in input, sort and skip nums[i] == nums[i-1] when the previous identical value was not used in this frame—classic duplicate-permutation guard.
Pattern D: grid / constraint (N-Queens flavor)
Partial state includes row, attacked columns, diagonals.
def is_safe(col, diag1, diag2, c, d1, d2):
return c not in col and d1 not in diag1 and d2 not in diag2
Talk track:
“I’ll place one queen per row. Columns and both diagonal families are sets I update on choose and undo on unchoose.”
Word search on a board is the same family: mark cell visited, recurse 4 directions, unmark.
What to say in the first five minutes
- “Output is all solutions / count / any—so I’ll record accordingly.”
- “Partial state is …” (path list, used array, sets)
- “Branching factor is …; prune when …”
- “Time is exponential in the worst case; I’ll prune aggressively.”
- Tiny dry-run: subsets of
[1,2]or permutations of[1,2]on the pad
Candidates commonly report that interviewers care more about clear undo and prune than about micro-optimizing constant factors. Keep company stories general.
Common bugs
- Forgetting
path.copy()(orpath[:]) when recording—every answer becomes the final path - Forgetting to undo (
pop,used[i]=False, unmark board) - Using combinations index rules for permutations (or vice versa)
- Duplicate inputs without skip logic → duplicate outputs
- Mutating global lists across test cases
- Pruning too late (after already recursing into illegal states)
Complexity honesty
Say “O(number of solutions × work per solution)” plus branching discussion. For subsets: O(n · 2^n). For permutations: O(n · n!). Do not claim polynomial time for full enumeration.
Freeze recovery
If you blank:
- Write
path = []anddef dfs(...): - Write the goal
ifandappend(path.copy()) - Write the for-loop with choose / dfs / unchoose empty comments
- Fill validity
- Only then add prunes
Talk track under freeze:
“I’ll get choose-explore-unchoose correct on a tiny example, then add the prune.”
Soft practice note
Backtracking fails in interviews when narration stalls, not only when code is wrong. If you want timed practice saying the template out loud until it is automatic, Luna Interview is built for calm rehearsal under pressure—practice and composure only, never anything that breaks interview rules.
Day-of checklist
- [ ] Goal condition clear (all / count / first)
- [ ] Choose → explore → unchoose written
- [ ] Record with a copy of the path
- [ ] Prune stated in one sentence
- [ ] Subsets vs combinations vs permutations distinguished
- [ ] Dry-ran a 2-element case by hand
Master the talk track first; the variants are the same skeleton with different candidate generators.
Rehearse with an AI interview copilot, then browse commonly reported interview questions.