How to calculate time complexity of backtracking algorithm?
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
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.
Related reading
- How to change edges' weight by designated rule?
- How to change the default collation of a table?
- How to check for repeating sequence in an integer
- How to check if a box fits into another box any rotations allowed
- How to change async method call to prevent forcing async up the call stack
- How to change max_allowed_packet size
- How to check if a number is a power of 2
- How to check if a number is a power of 2

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.