Pruning the search
In one line
Pruning cuts off branches of the search tree that cannot lead to a valid or better answer, which is what makes exponential backtracking fast enough in practice.
What it is
Pruning means proving early that a partial solution is hopeless and returning immediately instead of exploring everything below it. Cutting one branch near the root can remove millions of nodes.
There are a few kinds. Feasibility pruning stops when a rule is already broken (sum above target, queen attacked). Bound pruning, also called branch and bound, stops when even the best possible completion cannot beat the best answer found so far. Symmetry and duplicate pruning skips branches that are mirror images of ones already tried.
Ordering also matters: trying the most constrained or most promising choice first makes failures and good answers appear early, so more pruning happens later.
Why interviewers ask
The first backtracking solution in an interview is usually correct but too slow. Interviewers then ask how to make it faster, and the answer is almost always a pruning rule. Explaining why a rule is safe (it never removes a valid answer) shows real understanding.
How it works
- 1Feasibility check: before recursing, test whether the partial state already violates a rule; if so, skip this choice.
- 2Sort to enable early breaks: with positive numbers in ascending order, once one value is too large all later ones are too.
- 3Bound check: compute an optimistic estimate of the best completion (for example current value plus all remaining values); if it cannot beat the best so far, return.
- 4Duplicate and symmetry skip: if two choices lead to identical subtrees (same value at the same level, two empty buckets), try only one.
- 5Order choices: try large or highly constrained items first so dead ends are found near the root.
- 6Memoize failures when the same remaining state can be reached in different ways; at that point the search is turning into dynamic programming.
Worked example · Partition [4, 3, 2, 3, 5, 2, 1] into k = 4 groups of equal sum
- Total is 20, 20 % 4 == 0, so each group must sum to 5. The largest number is 5, which fits. Both checks happen before any search.
- Sort descending: [5, 4, 3, 3, 2, 2, 1]. Buckets start [0, 0, 0, 0]. Place 5 in bucket 0 -> [5, 0, 0, 0]. The other empty buckets are skipped by the seen set because an empty bucket is the same as any other.
- Place 4: bucket 0 would overflow (9), bucket 1 -> [5, 4, 0, 0]; buckets 2 and 3 are skipped as identical empty buckets.
- Place 3: buckets 0 and 1 overflow, bucket 2 -> [5, 4, 3, 0]. Place 3: bucket 2 would be 6, so bucket 3 -> [5, 4, 3, 3].
- Place 2: only bucket 2 fits -> [5, 4, 5, 3]. Place 2: only bucket 3 fits -> [5, 4, 5, 5]. Place 1: bucket 1 -> [5, 5, 5, 5].
- All numbers placed: return True. Without pruning there are 4^7 = 16,384 assignments; here the search went straight to the answer.
Picture it
Searching for lost keys: you do not check rooms you have not entered today, and you stop searching a room's drawers the moment you remember you never opened them. Every room you can rule out saves all the drawers inside it.
Reference code
def can_partition_k(nums, k):
total = sum(nums)
if total % k:
return False # prune before searching at all
target = total // k
nums = sorted(nums, reverse=True) # big items first fail fast
if nums[0] > target:
return False
buckets = [0] * k
def place(i):
if i == len(nums):
return True # every bucket is exactly target
seen = set()
for b in range(k):
if buckets[b] + nums[i] > target or buckets[b] in seen:
continue # overflow, or a twin bucket tried
seen.add(buckets[b])
buckets[b] += nums[i]
if place(i + 1):
return True
buckets[b] -= nums[i]
return False
return place(0)Four pruning rules: the divisibility and largest-item checks reject impossible inputs instantly, descending order makes big items fail fast, the overflow check is feasibility pruning, and the seen set skips buckets with the same current sum because they lead to identical subtrees (this also covers empty buckets).
Key patterns
Feasibility pruning
When: Rules can be checked on partial solutions
How: Check before recursing: sum not above target, cell not attacked, word prefix exists in a trie.
Branch and bound
When: Optimisation (min or max) problems
How: Keep the best answer so far; return when an optimistic bound on this branch cannot beat it.
Symmetry breaking
When: Interchangeable buckets, rows or colours
How: Try only one of several identical options, for example only the first empty bucket.
Order for fail-fast
When: Packing, partitioning, Sudoku
How: Place largest items or most constrained cells first so conflicts appear near the root.
Memoize dead states
When: The same remaining state repeats
How: Store failed states (for example a bitmask of used items) and return False immediately when seen again.
Real-world use
Chess engines
Engines like Stockfish use alpha-beta pruning on the game tree: once a move is shown to be worse than an alternative already found, its remaining replies are not searched. Good move ordering lets alpha-beta search far deeper than plain minimax in the same time.
Integer programming solvers
Solvers such as Gurobi, CPLEX and the open-source CBC use branch and bound: they solve a relaxed problem to get an optimistic bound and discard branches whose bound is worse than the best known solution.
SAT solvers
Modern SAT solvers learn a new clause from each conflict (conflict-driven clause learning), so the same dead end is never explored again in another part of the tree.
In a project
A cloud cost tool assigns 30 batch jobs with known CPU needs to the smallest number of identical servers (bin packing) every night.
- Start with a quick greedy answer (first-fit decreasing) to get an upper bound on the number of servers.
- Backtrack job by job, largest first, trying each server that still has room.
- Prune: skip servers with the same remaining capacity as one already tried, never open a second empty server for the same job, and stop a branch when used servers plus a lower bound (remaining CPU divided by capacity, rounded up) cannot beat the best answer.
- Cap the search time; if it runs out, keep the best answer found so far.
Impact: Pruning turns a search that would never finish into one that completes in well under a second for typical nights, and it often saves one or two servers compared with the greedy answer, which adds up to real monthly savings.
Trade-offs
Use it when
- A backtracking solution is correct but too slow
- You can state a rule that provably never removes a valid or better answer
- Optimisation problems where a cheap bound is available
Avoid it when
- The pruning check costs more than exploring the branch
- You cannot prove the rule is safe: an aggressive rule that drops valid answers gives wrong results
- The problem has polynomial structure (overlapping subproblems): use DP instead of a better-pruned search
Cost: Pruning rarely changes the worst-case big-O, which stays exponential, but it can reduce the explored nodes by orders of magnitude on real inputs. Each check should be O(1) or close to it.
Common mistakes
- Pruning after the recursive call instead of before it, which saves nothing.
- Using a bound that is not optimistic (it underestimates the best possible completion), which cuts branches that contain the real optimum.
- Skipping 'duplicates' that are not actually equivalent, losing valid answers.
- Claiming pruning improves the worst-case complexity when it only improves typical running time.
- Not mentioning ordering: the same pruning rule is far stronger when good choices are tried first.
Interview questions
Quick revision
- Prune before recursing, never after.
- Feasibility: rule already broken -> skip.
- Bound: best possible completion cannot beat best so far -> return.
- Sort ascending + break; or sort descending to fail fast in packing.
- Skip equivalent choices (same value at same level, identical buckets).
- Worst case stays exponential; typical speed improves hugely.
- Repeated states -> memoize -> it becomes DP.
Check yourself
1. What does branch and bound add to plain backtracking?
2. nums = [2, 2, 2, 2, 3], k = 2. What is the fastest correct conclusion?
3. Which pruning rule is unsafe?
4. How does pruning usually affect the worst-case time complexity of backtracking?
Related
Saved on this device. Create a free account to keep it on every device.
Practise this with Sam
A real mock interview, out loud, with an honest scorecard. Free to start.