The backtracking template
Choose, explore, un-choose — one skeleton that solves permutations, subsets and combinations.
Backtracking is a depth-first walk over the space of partial solutions. At each step you make a choice, explore everything that follows from it, then undo the choice and try the next one.
The skeleton never changes:
function backtrack(state, choices, results) {
if (isComplete(state)) {
results.push([...state]); // copy — state keeps mutating
return;
}
for (const choice of choices) {
if (!isValid(state, choice)) continue;
state.push(choice); // choose
backtrack(state, next(choices, choice), results);
state.pop(); // un-choose
}
}
The state.pop() is the backtracking. Forget it and every branch pollutes the next.
Permutations
function permutations(items) {
const results = [];
const used = new Array(items.length).fill(false);
const current = [];
const walk = () => {
if (current.length === items.length) { results.push([...current]); return; }
for (let i = 0; i < items.length; i++) {
if (used[i]) continue;
used[i] = true; current.push(items[i]);
walk();
current.pop(); used[i] = false;
}
};
walk();
return results;
}
O(n × n!) — there are n! permutations and copying each costs n.
Subsets
function subsets(items) {
const results = [];
const current = [];
const walk = (start) => {
results.push([...current]); // every node is an answer
for (let i = start; i < items.length; i++) {
current.push(items[i]);
walk(i + 1); // i + 1 prevents reuse and duplicates
current.pop();
}
};
walk(0);
return results;
}
O(n × 2ⁿ). The start parameter is what separates combinations (order does not matter) from permutations (it does).
The copy that catches everyone
results.push(current) pushes a reference to an array you are about to mutate — every result ends up identical and empty. Always [...current].
Handling duplicates
Sort the input, then skip a choice equal to its predecessor at the same level:
if (i > start && items[i] === items[i - 1]) continue;
That one line is the standard answer for "subsets II" and "permutations II".