Go through all permutations of an array recursively
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
Recursively generating all permutations of an array is a standard backtracking problem. The core idea is to fix one position at a time, try every possible element in that position, and recurse on the remaining positions.
This technique is valuable because it teaches two important ideas at once: recursion and backtracking. It also makes the growth in output size obvious, because an array of length n has n! permutations.
The Swap-and-Backtrack Approach
One classic recursive solution swaps elements in place. At recursion level start, you decide which element belongs at index start, swap it into position, recurse, and then swap back to restore the original state.
The second swap is the backtracking step. Without it, later recursive branches would start from a mutated array and the result would be wrong.
How the Recursion Tree Works
At the top level, every element gets a chance to occupy the first position. For each such choice, every remaining element gets a chance to occupy the second position, and so on.
For [1, 2, 3], the recursion conceptually explores:
- fix
1, then permute[2, 3] - fix
2, then permute[1, 3] - fix
3, then permute[1, 2]
The base case happens when start == len(arr). At that moment, every position has been fixed, so the current arrangement is one complete permutation.
Return a List Instead of Printing
Printing is useful for learning, but most real programs need to return the permutations.
This collects all permutations into memory. That is fine for small arrays, but remember that the total result count is n!, so memory usage grows quickly.
A Generator Version Is Often Better
If you want to iterate over permutations lazily, use yield instead of building one big list.
The generator version is often the most practical when you want to stream results into another algorithm rather than materialize them all at once.
What About Duplicate Values?
If the array contains repeated values, the simple swap approach will produce duplicate permutations. For example, [1, 1, 2] generates repeated outputs unless you skip repeated choices at each recursion depth.
One common approach is to track which values have already been used for the current start position.
That small addition prevents duplicate branches caused by identical values.
Complexity Matters
Any algorithm that generates every permutation must do at least n! work because the output itself contains n! items. The recursive overhead is usually not the real problem; the combinatorial explosion is.
That means recursive permutation generation is appropriate only when n is small or when you can stop early after finding what you need.
Common Pitfalls
The most common bug is forgetting to swap back after the recursive call. That breaks the backtracking logic and corrupts later branches.
Another issue is appending arr directly instead of arr[:] when saving a result. Without copying, every saved permutation points to the same list object, and all stored results end up identical.
People also underestimate how quickly n! grows. Even length 10 means 3,628,800 permutations, which is far too many for many practical tasks.
Finally, if duplicates are possible in the input, you need extra logic to avoid duplicate outputs.
Summary
- Recursive permutation generation usually uses swap-based backtracking.
- Fix one position, recurse on the rest, then swap back to restore state.
- Copy the array when recording a completed permutation.
- Use a generator when you want lazy iteration instead of storing every result.
- Be aware that the total number of permutations is
n!, so the method only scales to small inputs.
Related reading
- Gomoku array-based AI-algorithm?
- Good algorithm and data structure for looking up words with missing letters?
- Good algorithm for combining items from N lists into one with balanced distribution?
- Good algorithm for finding the diameter of a sparse graph?
- Good GetHashCode override for List of Foo objects respecting the order
- Good graph traversal algorithm
- Gram Schmidt with R
- Graph auto-layout algorithm

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.