Problem Statement
Permutations
You are given an array called nums that holds distinct integers (distinct means no number repeats). Your job is to return every possible ordering of those numbers. An ordering, also called a permutation, is just one way of lining up all the numbers. For example, [1,2,3] and [2,1,3] use the same numbers but in a different order, so they count as two different permutations. You can return the answers in any order.
Signals to notice
Brute force first
Not applicable — generating all permutations IS the problem. Output size is n!, which is unavoidable. It is a fair place to begin because it matches the surface of the question, yet it does not capture the deeper structure that makes the problem simpler.
The key insight
Backtracking: pick each unused element for the current position, recurse for remaining positions, then unpick. — one recursive call per permutation. Once you hold onto the right piece of information from moment to moment, the problem feels less like trial and error and more like following a shape that was there all along.
Trace it on nums=[1,2,3]
backtrack(current=[], remaining=[1,2,3]) -> not empty, start loop pick 1: current=[1], recurse remaining=[2,3] -> pick 2: current=[1,2], remaining=[3] -> pick 3: current=[1,2,3], remaining=[] EMPTY -> result=[[1,2,3]], pop back to [1,2] back at current=[1], pick 3: current=[1,3], remaining=[2] -> pick 2: current=[1,3,2], remaining=[] -> result+=[1,3,2]; pop back to [] pick 2: current=[2], remaining=[1,3] -> yields [2,1,3] then [2,3,1]; pop back to [] pick 3: current=[3], remaining=[1,2] -> yields [3,1,2] then [3,2,1]; pop back to [] loop over remaining exhausted -> return result = [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
What must stay true
At each position, try every element that hasn't been used yet. After exploring all choices for deeper positions, undo the choice (backtrack) and try the next element. When you keep that truth intact, each local choice supports the larger solution instead of fighting it.
Shape of the loop
function backtrack(current, remaining):
if remaining is empty: add copy of current to result; return
for i in 0..len(remaining)-1:
current.push(remaining[i])
backtrack(current, remaining without index i)
current.pop()Pseudocode only — the full worked solution lives in the Solution tab.
Easy way to go wrong
Not properly tracking which elements are used — a boolean array or set prevents reusing elements. Swapping elements in-place is an elegant alternative that avoids extra tracking. Most mistakes here are not about syntax; they come from losing track of what your state, pointer, or structure is supposed to mean.