N-Queens (LeetCode 51)
Placing n chess queens on an n x n board so that no two queens share a row, column, or diagonal is the classic n-queens puzzle.
Given n, return every distinct board arrangement that solves the puzzle, in any order.
Represent each solution as a list of row strings, where 'Q' marks a queen and '.' marks an empty square.
Worked Examples
n = 4[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]n = 1[["Q"]]⚖️Formal Constraints & Bounds
1 <= n <= 9
Core Insight
Main diagonal coordinates share a constant difference (r - c) and anti-diagonals share a constant sum (r + c). Using three O(1) lookup sets replaces full board scans with instant collision tests.
Real-World Scenario & Production Applications
Automated theorem proving, FPGA routing conflict resolution, register allocation in optimizing compilers.
Subproblems & Recurrence Decomposition3 Phases
Since no two queens can ever share a row, place exactly one queen per row and backtrack column-by-column within that row -- this alone cuts the search space from placing N queens anywhere to just choosing N column indices.
def backtrack(row):
if row == n:
record_solution()
return
for col in range(n):
if is_safe(row, col):
place(row, col)
backtrack(row + 1)
remove(row, col) # undo before trying next colStep-by-Step Execution Trace Table
| Step | Row | Candidate Col c | Conflict Check (cols, r-c, r+c) | Action | Placed Queens | Next State / Backtrack |
|---|---|---|---|---|---|---|
| 1 | 0 | c=1 | All clear: 1 ∉ cols, -1 ∉ diag1, 1 ∉ diag2 | Place Queen | [(0,1)] | Recurse row=1 |
| 2 | 1 | c=3 | All clear: 3 ∉ cols, -2 ∉ diag1, 4 ∉ diag2 | Place Queen | [(0,1), (1,3)] | Recurse row=2 |
| 3 | 2 | c=0 | All clear: 0 ∉ cols, 2 ∉ diag1, 2 ∉ diag2 | Place Queen | [(0,1), (1,3), (2,0)] | Recurse row=3 |
| 4 | 3 | c=2 | All clear: 2 ∉ cols, 1 ∉ diag1, 5 ∉ diag2 | Place Queen | [(0,1), (1,3), (2,0), (3,2)] | Recurse row=4 |
| 5 | 4 | — | Base case reached (r == 4) | ✅ Record Solution 1 | [".Q..", "...Q", "Q...", "..Q."] | Backtrack to row=3 |
| 6 | 3 | c=2 | Un-choose: remove c=2, r-c=1, r+c=5 | Revert . | [(0,1), (1,3), (2,0)] | Try next candidate |
n = 4[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]| Step | Row | Candidate Col c | Conflict Check (cols, r-c, r+c) | Action | Placed Queens | Next State / Backtrack |
|---|---|---|---|---|---|---|
| 1 | 0 | c=1 | All clear: 1 ∉ cols, -1 ∉ diag1, 1 ∉ diag2 | Place Queen | [(0,1)] | Recurse row=1 |
| 2 | 1 | c=3 | All clear: 3 ∉ cols, -2 ∉ diag1, 4 ∉ diag2 | Place Queen | [(0,1), (1,3)] | Recurse row=2 |
| 3 | 2 | c=0 | All clear: 0 ∉ cols, 2 ∉ diag1, 2 ∉ diag2 | Place Queen | [(0,1), (1,3), (2,0)] | Recurse row=3 |
| 4 | 3 | c=2 | All clear: 2 ∉ cols, 1 ∉ diag1, 5 ∉ diag2 | Place Queen | [(0,1), (1,3), (2,0), (3,2)] | Recurse row=4 |
| 5 | 4 | — | Base case reached (r == 4) | ✅ Record Solution 1 | [".Q..", "...Q", "Q...", "..Q."] | Backtrack to row=3 |
| 6 | 3 | c=2 | Un-choose: remove c=2, r-c=1, r+c=5 | Revert . | [(0,1), (1,3), (2,0)] | Try next candidate |
| 1 | cols, diag, anti = set(), set(), set() |
| 2 | for c in range(n): |
| 3 | if c in cols or (r - c) in diag or (r + c) in anti: |
| 4 | continue |
| 5 | place a queen at (r, c) and add c, r - c and r + c to the three sets |
| 6 | backtrack(r + 1) |
| 7 | remove the queen and remove c, r - c and r + c from the three sets |
Conceptual Narrative
🧭 Conceptual Foundation & Pattern Intuition
The N-Queens puzzle places non-attacking queens on an chessboard such that no two queens share the same row, column, or diagonal. A brute force that tests all placements is computationally impossible ( gives billion configurations). Backtracking drastically reduces this space by placing queens row by row: since every row must contain exactly one queen, we only ever test one queen per row. The challenge is checking diagonal attacks. Rather than scanning across the board in time for each placement, we use an instant coordinate hashing trick:
- Columns: Indexed directly by column .
- Major Diagonals (): Every square on a top-left to bottom-right diagonal shares the invariant .
- Minor Diagonals (): Every square on a top-right to bottom-left diagonal shares the invariant .
🏟️ The Analogy: Air Traffic Controllers on Runway Coordinates
Imagine an airport with intersecting runways laid out on a grid. You need to land airplanes simultaneously. To avoid radar collisions, no two planes can share the same horizontal latitude (row), vertical longitude (column), or flight paths tilted at (diagonals). An automated transponder assigns each landing plane three radio beacons: their column , their down-diagonal code , and their up-diagonal code . If any incoming plane's transponder matches an already occupied beacon, that landing site is instantly rejected.
🔑 Why It Works
By storing occupied coordinates in three small hash sets, the attack conflict check drops from board scans to one set lookup per line.
directional ray scanning trap: Scanning 8 directions across the 2D board on every placement ( per square). Using hash sets or bitmasks for
cols,diag1 (r - c), anddiag2 (r + c)reduces conflict checks to .Unnecessary 2D grid cell iteration: Iterating over both rows and columns simultaneously in the recursion loop ( branching). Because each row must contain exactly one queen, iterating row-by-row reduces the branching tree strictly to .
Asymmetric state cleanup on backtrack: Removing the column marker from
colsbut forgetting to remover - cfromdiag1orr + cfromdiag2, so later sibling branches are blocked by a queen that is no longer on the board.
4-Phase Thought Process Model
Pattern Recognition Signals
The 10-second spot
Place N queens on an N×N board so that no two attack each other: a row/column/diagonal constraint problem. Queens on one down-right diagonal share r - c, and queens on one down-left diagonal share r + c, so each line has a single number to track.
Formulating the Predicate & Invariants
Turning intuition into a boolean rule
Invariant: rows 0 to r - 1 each hold one queen, no two of them attack each other, and cols, diag and anti hold exactly their columns and diagonals.
Silent Failure Traps & Edge Cases
Where confident candidates still lose points
Forgetting to undo diagonal sets on backtrack: Both the column and both diagonal sets must remove the current position when backtracking out of a branch.
The 60-Second Interview Pitch
Say this out loud before you type a single line
I'd use Constraint Backtracking. Since each row must have exactly one queen, I place queens row-by-row from
r = 0ton - 1. I maintain three sets to detect attacks inO(1):colsfor column collisions,diagstoring(r - c)for down-right diagonals, andantistoring(r + c)for down-left diagonals. For each columncin rowr, ifc,r - candr + care not in the sets, I place the queen, add to all three sets, recurse onr + 1, and undo every mark on return. Whenr == n, I save a copy of the board. Runs in O(N!) time, with O(N^2) for the board andO(N)for the sets and the stack.
Complexity & Mathematical Proof
O(N!)
Look at the recursion tree: In row 0, we have N placement choices. Placing a queen eliminates 1 column and at least 1 diagonal direction from the next row. Thus, in row 1, at most N-1 candidate positions remain; in row 2, at most N-2 positions; down to row N-1 which has at most 1 position. The upper bound on tree nodes visited is strictly bounded by N · (N-1) · (N-2) ... 1 = O(N!). At each valid leaf solution (r = N), constructing the N x N string representation takes O(N^2) time. Multiplying the search space by board reconstruction yields O(N!) upper bounded search time.
O(N^2) board + O(N) sets and recursion stack, output not counted
Look at our memory allocations: We explore row-by-row from r = 0 to r = N, so the call stack consumes at most N frames: O(N). We maintain three hash sets (cols, diag, anti), each storing at most N integers: O(N) auxiliary space. The working 2D board matrix uses O(N^2) memory during search. Storing all S(N) solutions in the output list requires O(S(N) · N^2) space.
Derivation Progression
Placing a queen in row r removes its column and diagonal trajectories from subsequent rows, bounding branch width to N - r.
O(1) Collision LookupsMathematical invariants along diagonals avoid linear ray casting across the board on every step.
The permutation branching tree is strictly bounded by N!, eliminating over 99.999% of invalid grid combinations.
Variable Definitions
Dimension of the N x N chessboard and total number of queens to place
Total count of distinct valid non-attacking solutions (S(4)=2, S(8)=92, S(9)=352)
Memory Architecture & Bounds
O(N) Recursion frames bounded by board height N
O(N) For attack lookup sets (cols, diag, anti) + O(N^2) for working character grid
O(S(N) · N^2) To store all distinct string board configurations
Boundary Best / Worst Cases
for N = 1 (instant placement).
.
exhaustive state tree traversal to find all valid placements.
Decision & State-Space Search Tree
Senior SWE Deconstruction & Hardware Caveats
Triggers: "n queens on n x n chessboard", "no two queens attack each other". Grid Constraint Satisfaction: row-by-row placement with diagonal conflict testing using mathematical invariants: - Column invariant: - Main diagonal invariant: is constant along - Anti-diagonal invariant: is constant along .
. The search visits 2,057 calls of backtrack for (92 solutions), so the limit is tiny; the output grows with the number of solutions.
Scanning diagonals via loops costs per check; the sets make each check instead.
N-Queens (LeetCode 51)
Placing n chess queens on an n x n board so that no two queens share a row, column, or diagonal is the classic n-queens puzzle.
Given n, return every distinct board arrangement that solves the puzzle, in any order.
Represent each solution as a list of row strings, where 'Q' marks a queen and '.' marks an empty square.
Worked Examples
n = 4[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]n = 1[["Q"]]⚖️Formal Constraints & Bounds
1 <= n <= 9
Core Insight
Main diagonal coordinates share a constant difference (r - c) and anti-diagonals share a constant sum (r + c). Using three O(1) lookup sets replaces full board scans with instant collision tests.
Real-World Scenario & Production Applications
Automated theorem proving, FPGA routing conflict resolution, register allocation in optimizing compilers.
Subproblems & Recurrence Decomposition3 Phases
Since no two queens can ever share a row, place exactly one queen per row and backtrack column-by-column within that row -- this alone cuts the search space from placing N queens anywhere to just choosing N column indices.
def backtrack(row):
if row == n:
record_solution()
return
for col in range(n):
if is_safe(row, col):
place(row, col)
backtrack(row + 1)
remove(row, col) # undo before trying next colStep-by-Step Execution Trace Table
| Step | Row | Candidate Col c | Conflict Check (cols, r-c, r+c) | Action | Placed Queens | Next State / Backtrack |
|---|---|---|---|---|---|---|
| 1 | 0 | c=1 | All clear: 1 ∉ cols, -1 ∉ diag1, 1 ∉ diag2 | Place Queen | [(0,1)] | Recurse row=1 |
| 2 | 1 | c=3 | All clear: 3 ∉ cols, -2 ∉ diag1, 4 ∉ diag2 | Place Queen | [(0,1), (1,3)] | Recurse row=2 |
| 3 | 2 | c=0 | All clear: 0 ∉ cols, 2 ∉ diag1, 2 ∉ diag2 | Place Queen | [(0,1), (1,3), (2,0)] | Recurse row=3 |
| 4 | 3 | c=2 | All clear: 2 ∉ cols, 1 ∉ diag1, 5 ∉ diag2 | Place Queen | [(0,1), (1,3), (2,0), (3,2)] | Recurse row=4 |
| 5 | 4 | — | Base case reached (r == 4) | ✅ Record Solution 1 | [".Q..", "...Q", "Q...", "..Q."] | Backtrack to row=3 |
| 6 | 3 | c=2 | Un-choose: remove c=2, r-c=1, r+c=5 | Revert . | [(0,1), (1,3), (2,0)] | Try next candidate |
n = 4[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]| Step | Row | Candidate Col c | Conflict Check (cols, r-c, r+c) | Action | Placed Queens | Next State / Backtrack |
|---|---|---|---|---|---|---|
| 1 | 0 | c=1 | All clear: 1 ∉ cols, -1 ∉ diag1, 1 ∉ diag2 | Place Queen | [(0,1)] | Recurse row=1 |
| 2 | 1 | c=3 | All clear: 3 ∉ cols, -2 ∉ diag1, 4 ∉ diag2 | Place Queen | [(0,1), (1,3)] | Recurse row=2 |
| 3 | 2 | c=0 | All clear: 0 ∉ cols, 2 ∉ diag1, 2 ∉ diag2 | Place Queen | [(0,1), (1,3), (2,0)] | Recurse row=3 |
| 4 | 3 | c=2 | All clear: 2 ∉ cols, 1 ∉ diag1, 5 ∉ diag2 | Place Queen | [(0,1), (1,3), (2,0), (3,2)] | Recurse row=4 |
| 5 | 4 | — | Base case reached (r == 4) | ✅ Record Solution 1 | [".Q..", "...Q", "Q...", "..Q."] | Backtrack to row=3 |
| 6 | 3 | c=2 | Un-choose: remove c=2, r-c=1, r+c=5 | Revert . | [(0,1), (1,3), (2,0)] | Try next candidate |
| 1 | cols, diag, anti = set(), set(), set() |
| 2 | for c in range(n): |
| 3 | if c in cols or (r - c) in diag or (r + c) in anti: |
| 4 | continue |
| 5 | place a queen at (r, c) and add c, r - c and r + c to the three sets |
| 6 | backtrack(r + 1) |
| 7 | remove the queen and remove c, r - c and r + c from the three sets |
Conceptual Narrative
🧭 Conceptual Foundation & Pattern Intuition
The N-Queens puzzle places non-attacking queens on an chessboard such that no two queens share the same row, column, or diagonal. A brute force that tests all placements is computationally impossible ( gives billion configurations). Backtracking drastically reduces this space by placing queens row by row: since every row must contain exactly one queen, we only ever test one queen per row. The challenge is checking diagonal attacks. Rather than scanning across the board in time for each placement, we use an instant coordinate hashing trick:
- Columns: Indexed directly by column .
- Major Diagonals (): Every square on a top-left to bottom-right diagonal shares the invariant .
- Minor Diagonals (): Every square on a top-right to bottom-left diagonal shares the invariant .
🏟️ The Analogy: Air Traffic Controllers on Runway Coordinates
Imagine an airport with intersecting runways laid out on a grid. You need to land airplanes simultaneously. To avoid radar collisions, no two planes can share the same horizontal latitude (row), vertical longitude (column), or flight paths tilted at (diagonals). An automated transponder assigns each landing plane three radio beacons: their column , their down-diagonal code , and their up-diagonal code . If any incoming plane's transponder matches an already occupied beacon, that landing site is instantly rejected.
🔑 Why It Works
By storing occupied coordinates in three small hash sets, the attack conflict check drops from board scans to one set lookup per line.
directional ray scanning trap: Scanning 8 directions across the 2D board on every placement ( per square). Using hash sets or bitmasks for
cols,diag1 (r - c), anddiag2 (r + c)reduces conflict checks to .Unnecessary 2D grid cell iteration: Iterating over both rows and columns simultaneously in the recursion loop ( branching). Because each row must contain exactly one queen, iterating row-by-row reduces the branching tree strictly to .
Asymmetric state cleanup on backtrack: Removing the column marker from
colsbut forgetting to remover - cfromdiag1orr + cfromdiag2, so later sibling branches are blocked by a queen that is no longer on the board.
4-Phase Thought Process Model
Pattern Recognition Signals
The 10-second spot
Place N queens on an N×N board so that no two attack each other: a row/column/diagonal constraint problem. Queens on one down-right diagonal share r - c, and queens on one down-left diagonal share r + c, so each line has a single number to track.
Formulating the Predicate & Invariants
Turning intuition into a boolean rule
Invariant: rows 0 to r - 1 each hold one queen, no two of them attack each other, and cols, diag and anti hold exactly their columns and diagonals.
Silent Failure Traps & Edge Cases
Where confident candidates still lose points
Forgetting to undo diagonal sets on backtrack: Both the column and both diagonal sets must remove the current position when backtracking out of a branch.
The 60-Second Interview Pitch
Say this out loud before you type a single line
I'd use Constraint Backtracking. Since each row must have exactly one queen, I place queens row-by-row from
r = 0ton - 1. I maintain three sets to detect attacks inO(1):colsfor column collisions,diagstoring(r - c)for down-right diagonals, andantistoring(r + c)for down-left diagonals. For each columncin rowr, ifc,r - candr + care not in the sets, I place the queen, add to all three sets, recurse onr + 1, and undo every mark on return. Whenr == n, I save a copy of the board. Runs in O(N!) time, with O(N^2) for the board andO(N)for the sets and the stack.
Complexity & Mathematical Proof
O(N!)
Look at the recursion tree: In row 0, we have N placement choices. Placing a queen eliminates 1 column and at least 1 diagonal direction from the next row. Thus, in row 1, at most N-1 candidate positions remain; in row 2, at most N-2 positions; down to row N-1 which has at most 1 position. The upper bound on tree nodes visited is strictly bounded by N · (N-1) · (N-2) ... 1 = O(N!). At each valid leaf solution (r = N), constructing the N x N string representation takes O(N^2) time. Multiplying the search space by board reconstruction yields O(N!) upper bounded search time.
O(N^2) board + O(N) sets and recursion stack, output not counted
Look at our memory allocations: We explore row-by-row from r = 0 to r = N, so the call stack consumes at most N frames: O(N). We maintain three hash sets (cols, diag, anti), each storing at most N integers: O(N) auxiliary space. The working 2D board matrix uses O(N^2) memory during search. Storing all S(N) solutions in the output list requires O(S(N) · N^2) space.
Derivation Progression
Placing a queen in row r removes its column and diagonal trajectories from subsequent rows, bounding branch width to N - r.
O(1) Collision LookupsMathematical invariants along diagonals avoid linear ray casting across the board on every step.
The permutation branching tree is strictly bounded by N!, eliminating over 99.999% of invalid grid combinations.
Variable Definitions
Dimension of the N x N chessboard and total number of queens to place
Total count of distinct valid non-attacking solutions (S(4)=2, S(8)=92, S(9)=352)
Memory Architecture & Bounds
O(N) Recursion frames bounded by board height N
O(N) For attack lookup sets (cols, diag, anti) + O(N^2) for working character grid
O(S(N) · N^2) To store all distinct string board configurations
Boundary Best / Worst Cases
for N = 1 (instant placement).
.
exhaustive state tree traversal to find all valid placements.
Decision & State-Space Search Tree
Senior SWE Deconstruction & Hardware Caveats
Triggers: "n queens on n x n chessboard", "no two queens attack each other". Grid Constraint Satisfaction: row-by-row placement with diagonal conflict testing using mathematical invariants: - Column invariant: - Main diagonal invariant: is constant along - Anti-diagonal invariant: is constant along .
. The search visits 2,057 calls of backtrack for (92 solutions), so the limit is tiny; the output grows with the number of solutions.
Scanning diagonals via loops costs per check; the sets make each check instead.