← All Lessons Lesson 2 / 21
Lesson 2

The Key Components of Backtracking

The Key Components of Backtracking

Backtracking is a way of solving problems by trying things out. You make a choice, see where it leads, and if it leads to a dead end, you go back and try a different choice. To understand how this really works, it helps to break a backtracking solution into its main parts.

A problem must satisfy three conditions before backtracking is a good fit. When all three are present, they naturally produce something called a state space tree, which is the backbone of the whole solution. Let's look at each piece.

1. A Finite Set of Outcomes

Backtracking is a brute-force technique. "Brute force" just means we don't use a clever shortcut — instead we are willing to generate and check every possibility one by one.

For this to work, the problem must have two qualities:

  • Deterministic — the same choice always gives the same result. There is no randomness. If you pick the digit 0, you get 0 every time.
  • A finite set of outcomes — the list of possible answers must come to an end. If there were infinitely many possibilities, we could never finish checking them all.

Think of a 4-digit phone password. Every position can be a digit from 0 to 9, and there are only 4 positions. That gives a fixed, countable number of possible passwords. It is large, but it ends — so it is a finite set. Somewhere inside that big set of possibilities sits the one true solution we are looking for.

2. A Way to Validate a Solution

Generating every possible outcome is only half the job. We also need a way to check each outcome and ask: *"Is this one actually a valid solution?"*

This check is done by a validation function. You hand it one outcome, and it answers in one of two ways:

  • This is a valid solution
  • This is not a valid solution

For the password example, the validation function would take a guessed 4-digit code and report whether it unlocks the phone. Without such a function, we would have no way to tell a correct answer apart from a wrong one. So every backtracking problem needs some rule or function that recognizes a solution when it sees one.

3. A Recursive Structure

Backtracking builds an answer step by step. You start from the original problem, make one choice, then make another, and keep going. Each choice turns the problem into a slightly smaller version of itself.

But what happens when a series of choices leads to a wrong result? You must be able to step back — undo the last choice — and try a different one. This "go forward, then step back" behavior is exactly what recursion gives us for free.

Here is why recursion fits so well:

  1. Every function call is one choice. Calling the function means "I commit to this option and move forward."
  2. The function call stack remembers all the choices. The stack is like a stack of plates — each call sits on top of the one before it. So the path of choices from the start to where you are now is always recorded.
  3. Returning from a call steps back one level. When a function call finishes, control goes back to the function that called it. From there you can make a *different* choice by calling the function again with different inputs.

So the pattern is: make choices while going ahead, and backtrack and update choices when a path fails. The problem shrinks into smaller problems until it reaches a base case — the simplest version where no more choices are needed.

How These Combine: The State Space Tree

When you run a backtracking solution, all the choices you make and unmake naturally form a tree. This is called a state space tree.

A "state" is just a snapshot of the problem at one moment — what choices you have made so far. The tree is built like this:

  • The root is the starting point, called the problem state (no choices made yet).
  • Each branch is one choice you could make.
  • The leaves at the bottom are terminal states — complete potential solutions, ready to be validated.

The states in between can be one of two kinds:

  • A fulfilling state — a state that *can still lead* to a solution. It is worth exploring further.
  • A defying state — a state that *cannot* lead to a solution. The moment we reach one, we stop and backtrack, because going deeper would waste time.

We decide whether a state is fulfilling or defying using a rule that is specific to the problem. (Note: not every backtracking problem needs to label its states this way — some simply explore all paths.)

The algorithm explores the tree like this: start at the root, walk down through fulfilling states, and backtrack the instant you hit a defying state or a dead end. When you reach a terminal state at the bottom, run the validation check, then backtrack again to explore other paths — until every possible solution has been found.

The Tree for the Phone Password

Picture the 4-digit password problem, but simplified to digits 0 and 1. Starting from the empty problem state, each level adds one more digit:

  • Level 1: choose 0 or 1"0" or "1"
  • Level 2: add another → "00", "01", "10", "11"
  • Level 3: → "000", "001", ... "111"
  • Level 4 (leaves): full 4-digit codes like "0000", "0001", ... "1111", each one ready to validate.

Every leaf is a complete password we can test. In this particular example, there are no defying states — every partial code could still grow into some valid full code, so we never have to cut a branch early. We simply build all the codes and validate each one at the bottom.

This is the heart of backtracking: a finite set of outcomes gives us a tree to explore, a validation function tells us when we have found a real answer, and recursion lets us walk down the tree and step back whenever we need to.

The Key Components of Backtracking
Diagram — click to zoom (scroll / drag to pan)