Backtracking finds every solution — or one that works — by building it one choice at a time. At each step it tries a choice, carries on with the rest, and when that line of choices is finished or turns out to be a dead end, it undoes the choice and tries the next. It's how you'd solve a maze by hand: walk forward, and at a dead end, go back to the last fork and take another path.
Every backtracking function has the same three moves around a recursive call:
When the path is complete — here, when it holds n bits — it's an answer: copy it into the results and return. The function never needs to know how deep it is in the tree; the path and the recursion remember that.
The tree grows as the search goes deeper; each time a choice is undone, the search backs up to the last fork.
function binaryStrings(n) { const result = []; const path = []; // the choices made so far const build = () => { if (path.length === n) { // a full string: record it result.push(path.join("")); return; } for (const bit of ["0", "1"]) { path.push(bit); // choose build(); // explore path.pop(); // un-choose } }; build(); return result;}Backtracking is a depth-first traversal of the decision tree — the call stack holds the current path from the top down to where the search is. Nothing else is stored: the tree is never built in memory, only walked.