N-Queens
N-Queens is a backtracking problem: place one queen in every row of an n x n chessboard so that no two queens share a column or diagonal. The solver tries columns left to right, abandons a candidate at the first conflict, and undoes earlier choices when a row has nowhere legal to go.
Think of each placed queen signing three ledgers. One records its column, one records row - col, and one records row + col. A new queen may sit only if all three signatures are absent. When a branch fails, you erase the departing queen from every ledger. Miss one erasure and the paperwork starts rejecting queens that do not exist.
How N-Queens backtracking works
The solver assigns rows in order. That decision quietly removes one entire constraint: two queens can never share a row because the recursion places exactly one queen before calling search(row + 1). The remaining attacks have compact keys:
- Queens in the same column have the same
col. - Queens on a
\diagonal have the samerow - col. - Queens on a
/diagonal have the samerow + col.
Three sets make each safety check O(1). If any key is already present, the candidate is rejected without changing the board. A safe candidate is appended to queens, then its three keys enter the sets. If the recursive call succeeds, that result propagates outward. If it fails, the solver pops the queen and removes all three keys before trying the next column.
That last sentence is the backtracking invariant: after a failed recursive call, the caller must see exactly the state it had before making the choice. Backtracking is not vague "going backward." It is a precise rollback.
This shape turns up wherever constraints can be checked incrementally and rolled back cheaply: Sudoku, timetable and resource assignment, backtracking regex engines, and the decision search inside SAT or constraint-programming solvers. The state looks different, but the contract is the same: choose, reserve, recurse, then restore every reservation on failure.
This lesson stops at the first solution. It does not enumerate every solution, use symmetry to skip mirrored boards, or pack constraints into bitmasks. Those are useful extensions, but they are different machines.
N-Queens step by step
The default board is n = 4, with columns tried in order 0, 1, 2, 3.
search(0)tries(0, 0). All three ledgers are empty, so the queen is placed and the solver descends to row 1.- Row 1 rejects
(1, 0)because column 0 is occupied. It rejects(1, 1)because both squares haverow - col = 0. Candidate(1, 2)is safe, so the prefix is now[0, 2]. - Row 2 has no legal column. Column 0 is occupied; column 1 meets the queen at
(1, 2)on a/diagonal; column 2 is occupied; column 3 meets(1, 2)on a\diagonal. The row returns false. - The solver removes
(1, 2)and releases its column and diagonal keys. Row 1 resumes at column 3, places(1, 3), and descends again. - Row 2 places
(2, 1), but row 3 then rejects all four columns. The solver undoes(2, 1). Row 2 has no later legal choice, so it returns false; row 1 then undoes(1, 3)as well. - Row 1 is exhausted. The first queen at
(0, 0)is removed. This is the important rollback: the board and all three ledgers are empty again before row 0 tries its next column. - Row 0 places
(0, 1). Row 1 rejects columns 0, 1, and 2, then places(1, 3). Row 2 places(2, 0). Row 3 rejects columns 0 and 1, then places(3, 2). - The recursion reaches row 4, which is the base case. The returned column vector is
[1, 3, 0, 2]: row 0 uses column 1, row 1 uses column 3, row 2 uses column 0, and row 3 uses column 2.
The run checks 26 candidate squares, makes 8 provisional placements, and performs 4 backtracks. Its 18 immediate conflict rejections prevent 114 raw suffix assignments from ever being generated. For comparison, an unconstrained four-row board has 4^4 = 256 complete row assignments, while enforcing unique columns leaves 4! = 24 complete permutations. Those are different units: 26 counts candidate nodes visited; 256 and 24 count complete boards.
On the board, one red conflict line names the queen that blocks the current candidate. An X means the candidate failed a key check immediately and never owned a queen. A rollback ring means the candidate was legal, the solver searched below it, and that subtree later failed. The right panel draws the future row choices behind a rejection, so 4 x 4 = 16 means sixteen descendant row assignments never come into existence.
Time and space complexity
| Measure | Bound | Reason |
|---|---|---|
| Candidate space with unique columns | O(N!) | One queen per row and unique columns reduce the raw N^N row assignments to permutations; diagonal checks prune many prefixes earlier. |
| Time complexity of this code | O(N × N!) upper bound | Every surviving prefix still scans all N columns of the next row. |
| Candidate safety check | O(1) expected | Three hash-set membership tests replace scanning every placed queen. |
| Auxiliary space | O(N) | At most N queens, N recursive calls, and O(N) occupied keys live at once. |
The exact work depends heavily on column order. With the same left-to-right code, n = 4 backtracks four times before its first solution, while n = 5 reaches [0, 2, 4, 1, 3] without a single undo. A larger board is not automatically a harder first-solution trace.
Use this direct set-backed search when you need one valid assignment and the search tree is small enough to tolerate. Asking for every solution removes the successful early return: record each board and keep searching, which means paying for the remaining viable tree. For larger N, bitmasks and symmetry cuts are the usual next steps; for richer scheduling or allocation rules, a constraint-programming or SAT solver is often the honest tool.
Edge cases
n = 1has the immediate solution[0].n = 2andn = 3have no solution. The solver must exhaust row 0 and returnNonein Python ornullin JavaScript with every set empty.- The canvas accepts
1 <= n <= 5so individual candidates remain readable. That is a visualization limit, not an algorithmic limit. - Changing the column order can change both the first solution and the number of backtracks, even though the set of valid boards is unchanged.
- This implementation returns one solution. To collect all solutions, a successful base case must record a copy and continue searching instead of returning immediately.
Common mistakes
- Undoing only the board. Popping
queenswithout deleting the column and both diagonal keys leaves stale constraints. Valid branches then look illegal. - Using the wrong diagonal formulas.
row - colis constant on\diagonals;row + colis constant on/diagonals. Swapping the names is harmless if the checks stay consistent, but mixing the formulas between add and remove corrupts the state. - Returning false after the first failed child. A failed column means "try the next column," not "this row is impossible." The false return belongs after the loop.
- Mutating on rejection. A conflicting candidate never enters
queensor any set. Rejecting and then "cleaning up" creates extra state transitions and invites mismatched deletes. - Forgetting what the result vector means. The index is the row and the stored value is the column.
[1, 3, 0, 2]is a board, not a sequence of queen IDs.
Keep exploring
A few lessons that share the same technique or lead into the next idea.
Premium players need paid access. Every Explain doc is free.
Found a mistake or something unclear? Leave feedback.