skip to content

Recursion & Backtracking

Recursive thinking as its own subject: how recursive calls actually execute, when iteration is the better tool, and how divide-and-conquer and backtracking build on the same machinery. Interviewers probe this because most tree, graph, and combinatorial problems fall apart without a solid recursive mental model.

part ofData structures & algorithmsoverview, primer and where to startread it →
on this pageshow

explore

questions

page 2 of 2

In a game-move tree with 3 legal moves per position, what does searching one ply deeper cost?

level: middleimportance: should knowfreq 48%

basics

~20 s

One extra ply multiplies the whole search by about three: each position at the current frontier fans out into three more. Depth-limited search cost is dominated by the deepest level, so deepening is a multiplication, never an increment.

open as a page

Why does a naive explicit-stack rewrite lose the work a recursion does after its recursive calls?

level: middleimportance: should knowfreq 42%

basics

~20 s

Pushing children captures only the descent. A real frame also remembers where to resume, because the parent still owes work once its children finish. Push each node twice with a phase tag so the parent is revisited after its subtree completes.

open as a page

Why do many runtimes decline tail-call elimination despite the free stack win?

level: middleimportance: should knowfreq 38%

basics

~10 s

Eliminating a tail call discards the caller's activation record, and those records are what stack traces, debuggers, profilers and caller-chain security checks read. Runtimes that prize diagnosability refuse the trade deliberately, not by oversight.

open as a page

Quicksort blows the stack on a year of already-ordered sensor timestamps — how do you bound its recursion depth?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Ordered input makes every split lopsided, so the recursion holds one frame per record. Recurse into the smaller partition and loop on the larger — the smaller side is at most half, capping depth at log n.

open as a page

In a divide-and-conquer closest-pair search over drop coordinates, what must the combine step do?

level: seniorimportance: should knowfreq 38%

basics

~20 s

The combine step must check pairs that straddle the dividing line, since the closest pair overall may have one point on each side. It stays cheap by using the recursion's own distance to bound the search to a narrow band.

open as a page

Generating permutations of a multiset, why must sort-and-skip test that the earlier twin is unused?

level: seniorimportance: should knowfreq 55%

basics

~20 s

Sorting makes equal items adjacent so the check can be local. The guard then fixes one canonical order among identical items: a twin may only be placed once its left neighbour already is. Reverse the test and the second twin can never be placed at all.

open as a page

Searching a grid for many target sequences at once, why prune on prefixes rather than full matches?

level: seniorimportance: should knowfreq 41%

basics

~20 s

A membership test only rules a branch out at full target length, by which point the whole subtree has already been explored. A prefix test rules it out at depth d and discards everything beneath — and the subtree beneath is where all the cost lives.

open as a page

In backtracking, when is copying the state into each call better than mutating and undoing?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Copy when the state is small or the recursion shallow, buying safety with the constant factor. Copying costs the state's size at every node and one live copy per level; mutate-and-undo costs little but demands a restore on every exit.

open as a page

A backtracking enumerator exhausts memory collecting every valid roster — what do you change?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Stop materialising the output. Every arrangement here is valid, so nothing can be cut from the search; the memory goes on the returned collection. Hand each solution to a consumer at the leaf, or fold it into a count or aggregate.

open as a page

Why can a digit-stripping recursion with an n == 0 base case never terminate on negative input?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Because the termination argument silently assumes integer division rounds toward zero. Under rounding toward negative infinity the value sticks at -1 and never equals 0. Negating the input first is not a safe fix: the most-negative fixed-width value has no positive counterpart.

open as a page

Your recursive log parser passed every test, then died at 3 a.m. on a million-record chain — why was that inevitable?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Recursion depth tracked input size, so thousand-record fixtures held a thousand frames while the production chain demanded a thousand times more than the stack region could hold. Stack exhaustion has no warning curve: it works, then it aborts.

open as a page

In a drawn game-search tree, how do you tell that different move orders re-explore the same position?

level: seniorimportance: should knowfreq 56%

basics

~20 s

Label every node with the arguments the invocation received — the position and the remaining depth — instead of with the move that led there. Repeated labels are repeated work: identical labels have identical subtrees beneath them.

open as a page

Your recursive catalogue walk overflowed the stack in production — do you convert it to an explicit stack?

level: seniorimportance: should knowfreq 40%

basics

~20 s

First establish whether the depth was legitimate. If real data is genuinely that deep, an explicit stack moves the frames into memory that grows on demand and fixes it. If a cycle or bad parent link caused it, conversion only turns a fast crash into an out-of-memory.

open as a page

Before relying on tail-call elimination for unbounded input, what must you establish?

level: seniorimportance: should knowfreq 33%

basics

~20 s

A specified guarantee from the target, plus its scope: self-recursion only or general tail calls, which build modes it covers, whether the call still qualifies inside exception handlers. A large passing test is an observation, not a guarantee.

open as a page

When is a divide-and-conquer rewrite worth it over a working quadratic scan of a few thousand points?

level: principalimportance: should knowfreq 33%

basics

~20 s

When measured headroom, not asymptotics, says so. A quadratic scan over a few thousand points is a few million tight comparisons and often fits the budget; the decision turns on projected growth, tail latency today, and maintenance risk.

open as a page

Your feature-flag test matrix has 30 flags — do you still enumerate all 2^n configurations?

level: principalimportance: should knowfreq 38%

basics

~20 s

No. Thirty flags means over a billion configurations, and no pruning trick rescues an exponent you have no constraints to prune with. The work becomes scoping: enumerate only within interacting groups, encode real constraints, cover the rest pairwise, and cap flag growth.

open as a page

A pruned backtracking search must run inside a request latency budget — how do you decide whether it can ship?

level: principalimportance: should knowfreq 33%

basics

~20 s

Pruning improves the average case, never the exponential worst case, so measurements on today's traffic cannot promise a latency bound. Ship only behind a bounded input size, a hard node budget with a defined fallback answer, and alerting on cap-hits.

open as a page

Recursion overflows on deeply skewed input: how do you choose between an explicit stack, reshaping the data, or capping depth?

level: principalimportance: should knowfreq 38%

basics

~20 s

Decide by what removes the failure class versus what the team can maintain. Reshaping the data bounds depth permanently but touches producers; an explicit stack keeps the algorithm and relocates linear state; caps buy time with a documented rejection.

open as a page

To list every k-person roster from n engineers, how do include-exclude and index-loop recursions differ?

level: middleimportance: nice to knowfreq 32%

basics

~20 s

Both emit the same rosters. Include-exclude asks one in-or-out question per engineer, giving a binary tree of depth n. The index-loop picks the next member from those after the last chosen, giving a tree of depth k with wide fan-out.

open as a page

What does forward checking add to a backtracking search beyond validating the current assignment?

level: seniorimportance: nice to knowfreq 28%

basics

~20 s

Plain checking looks backward, confirming the new assignment conflicts with nothing already chosen. Forward checking looks ahead: it deletes the newly illegal values from the domains of variables not yet assigned, and backtracks the moment any of those domains becomes empty.

open as a page

showing 31–50 of 50