How to calculate time complexity of backtracking algorithm?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Backtracking is a crucial algorithmic technique used to solve problems where other methods (greedy, dynamic programming) may not apply due to the lack of optimal substructure or overlapping subproblems. Determining the time complexity of backtracking algorithms is essential for evaluating their efficiency and understanding when they are practical. This article walks through the process of calculating time complexity for backtracking algorithms with concrete examples.
Understanding Backtracking
Backtracking algorithms methodically explore all possible configurations of a problem to find a solution (or all solutions). They build a solution incrementally and abandon ("backtrack") a path as soon as it is determined that it cannot lead to a valid solution.
Basic Structure
- Decision Point: At each step, the algorithm chooses from a set of options.
- Constraint Check (Pruning): Before exploring a choice, the algorithm checks if it violates any constraints. If it does, that entire subtree is skipped.
- Recursive Exploration: The algorithm recursively explores each valid choice and backtracks upon reaching a dead end.
The General Time Complexity Formula
The time complexity of backtracking is determined by the number of nodes visited in the implicit decision tree. The two key factors are:
- Branching factor : the number of choices at each decision point
- Depth : the maximum depth of the decision tree (typically the size of the input)
The worst-case time complexity (without pruning) is:
This represents the total number of leaf nodes in a complete tree of depth with branching factor . Each path from root to leaf represents one complete exploration of a potential solution.
Worked Example: N-Queens Problem
The N-Queens problem involves placing queens on an chessboard so that no two queens threaten each other.
Analysis
- Branching factor: At row , we can place a queen in any of columns. So at the first level.
- Depth: There are rows, so .
- Pruning effect: Due to the constraint that no two queens can share a column or diagonal, the number of valid positions decreases at each level.
Without pruning, the complexity would be . But column constraints alone reduce it to:
because the first queen has column choices, the second has (it cannot share the first queen's column), the third has , and so on:
With diagonal pruning, the actual number of explored nodes is even smaller in practice, but remains the standard worst-case bound.
Worked Example: Generating All Subsets
Given a set of elements, generate all possible subsets.
Analysis
- Branching factor: At each element, we have 2 choices (include or exclude).
- Depth: elements to decide on.
Time complexity: , since we explore every combination.
Worked Example: Permutations
Given elements, generate all permutations.
Analysis
- At level 0, we choose from elements.
- At level 1, we choose from remaining elements.
- This continues down to 1 choice at level .
Time complexity: , matching the number of permutations.
Impact of Pruning
Pruning is what makes backtracking practical. Without pruning, backtracking degenerates into brute-force enumeration. With good pruning:
- Entire subtrees are eliminated early
- The effective branching factor is reduced
- The practical runtime can be orders of magnitude faster than the theoretical worst case
However, analyzing the exact complexity with pruning is usually problem-specific and often requires empirical measurement or amortized analysis.
Summary
| Problem | Branching Factor | Depth | Time Complexity |
| N-Queens | (reducing) | ||
| All Subsets | |||
| Permutations | (reducing) | ||
| General case |
Additional Considerations
- Space complexity: Usually for the recursion stack, where is the depth of the tree.
- Per-node work: If each node requires work (e.g., copying an array), the total complexity becomes .
- Constraint propagation: Advanced techniques like arc consistency (used in Sudoku solvers) can dramatically reduce the search space beyond simple pruning.
- Memoization: When subproblems overlap, adding memoization transforms backtracking into dynamic programming, potentially reducing exponential time to polynomial time.
Understanding the time complexity of backtracking algorithms helps you predict whether a brute-force search will finish in a reasonable time for a given input size, and guides you toward the right optimizations when it will not.

