52 - N-Queens II
Difficulty: Hard | Pattern: Backtracking | Company tags: Amazon, Google, Microsoft
Problem Statement
The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two queens attack each other.
Given an integer n, return the number of distinct solutions to the n-queens puzzle.
Example 1:
Input: n = 4
Output: 2
Example 2:
Input: n = 1
Output: 1
Solution: Backtracking with Sets — O(n!), O(n)
Key insight: A queen attacks along its column, and two diagonals. Track:
cols: set of occupied columnsdiag1: set of occupied(row - col)diagonals (top-left to bottom-right)diag2: set of occupied(row + col)diagonals (top-right to bottom-left)
def totalNQueens(n: int) -> int:
count = 0
cols = set()
diag1 = set() # row - col
diag2 = set() # row + col
def backtrack(row):
nonlocal count
if row == n:
count += 1
return
for col in range(n):
if col in cols or (row - col) in diag1 or (row + col) in diag2:
continue
cols.add(col)
diag1.add(row - col)
diag2.add(row + col)
backtrack(row + 1)
cols.remove(col)
diag1.remove(row - col)
diag2.remove(row + col)
backtrack(0)
return count
Algorithm Flow
Dry Run (n=4)
Row 0: try col 0,1,2,3
- col=1: place at (0,1); row 1 try col 3 → (1,3); row 2 try col 0 → (2,0); row 3 try col 2 → (3,2) ✓ solution 1
- col=2: place at (0,2); row 1 try col 0 → (1,0); row 2 try col 3 → (2,3); row 3 try col 1 → (3,1) ✓ solution 2
Result: 2 ✓
Difference from N-Queens I (LC 51)
LC 51 returns all board configurations. LC 52 only returns the count, so we avoid building the board representation — just increment count.
Complexity
- Time: O(n!) — each queen eliminates options for the next row
- Space: O(n) — sets and recursion stack
Key Terms
| Term | Definition |
|---|---|
| Backtracking | Incrementally build a candidate placement and abandon (undo) a branch as soon as it violates a constraint. |
| Diagonal conflict tracking | Every cell on the same \ diagonal shares row - col; every cell on the same / diagonal shares row + col, letting conflicts be checked in O(1). |
| State-space pruning | Skipping columns already marked unsafe avoids exploring branches that can never yield a valid solution. |
| Bitmasking (optimization) | Represent cols, diag1, diag2 as integers and use bitwise AND/OR to find and mark available columns in O(1) per row, faster than sets in practice. |
| Symmetry pruning | Solutions for columns 0..n/2 mirror solutions for n/2..n, so only half the first row needs to be searched (with special handling for odd n's middle column). |
FAQ
Q1: Why does LC 52 avoid building the board while LC 51 does?
LC 52 only needs a count, so allocating and copying an n x n board per solution would be wasted work; a single integer counter suffices.
Q2: Why use row - col and row + col instead of tracking full diagonal coordinates?
Every cell on the same anti-diagonal or main diagonal shares one of these two invariants, so a single set membership check replaces an O(n) diagonal scan.
Q3: Can this be solved faster than O(n!) in the worst case?
Not asymptotically — the search space is inherently combinatorial — but bitmasking and symmetry pruning cut the constant factor significantly, which matters for larger n in interviews and benchmarks.
Q4: What's the base case and why does it return without placing anything?
row == n means all n rows have valid queens placed, so the recursion increments count and returns — there's nothing left to place.
Q5: How would you extend this solution to also return one example board instead of just the count?
Track a board list of column choices per row, and when row == n, convert it into the LC 51 string-grid format and return/store it instead of (or alongside) incrementing a counter.
Quick Revision
- Problem: count valid ways to place n non-attacking queens on an n x n board.
- Pattern: backtracking, one queen per row, try each column.
- Track conflicts in O(1) using three sets:
cols,diag1(row-col),diag2(row+col). - Place a queen, recurse to the next row, then undo (remove) before trying the next column.
- Base case:
row == nmeans a full valid placement — incrementcount. - No board construction needed since only the count is required (unlike LC 51).
- Time: O(n!); Space: O(n) for sets and recursion depth.
- Optimization: replace sets with bitmasks for column/diagonal availability to speed up constant factors.
- n=4 gives 2 solutions; n=1 gives 1; n=2 and n=3 give 0 (no valid arrangement exists).
Related Problems
- 51 - N-Queens — same constraint-satisfaction setup, but returns the actual board configurations instead of just the count.
- Sudoku Solver — another classic backtracking-with-constraint-sets problem (row/col/box conflict tracking).
- Combination Sum / Permutations — simpler backtracking templates that build up the same "choose, recurse, undo" pattern used here.