A Three-Slot Template Turns Every Backtracking Problem into Fill-in-the-Blanks
Interview loops on LeetCode 46 are common because candidates treat each backtracking variant as a new problem instead of recognizing a single parameterized skeleton. Memorizing three diffs on one template eliminates the rewrite-from-scratch cycle and directly answers the standard follow-up: "Now modify it for combinations."
Backtracking is often rewritten from scratch by intuition, leading to the same bugs: missing undo steps, reference-copy failures, and forgotten termination conditions. A universal template isolates the three decision points that differ across problem types — when to record a result, where to begin the loop, and what to skip. Permutations use a `used[]` array and always start from zero; combinations and subsets use a `start` parameter that only moves forward, preventing duplicate sets. Subsets differ from combinations solely by recording at every node rather than only at a fixed depth.
The template exposes why `result.push([...path])` is mandatory in JavaScript: pushing the `path` reference means every stored result mutates when `pop()` runs later. The same structure handles deduplication for repeated elements by sorting and checking adjacent values. Decision trees make the time complexities visible — O(n!) for permutations, O(2^n) for subsets, and O(C(n,k)) for combinations — each corresponding to the number of nodes traversed.
The template reveals that the core difference between problem types is just the iteration domain — full set versus suffix — which is a simpler mental model than memorizing separate algorithms.
JavaScript's reference semantics turn a missing spread operator into a silent data-corruption bug that produces empty arrays without throwing an error, making it a disproportionately common failure in coding interviews.
Teaching backtracking through decision-tree diagrams makes the time complexity derivable by inspection: count the nodes, and you have the bound.