N-Queens

HardBacktracking · Constraint Pruning🧩 BacktrackingLeetCode #51 ↗Updated

Problem

Place n chess queens on an n × n board so that no two attack each other (no shared row, column or diagonal). Return every distinct arrangement, each drawn as n strings where 'Q' is a queen and '.' is an empty square.
Inputn=4Output[[".Q..","...Q","Q...","..Q."], ["..Q.","Q...","...Q",".Q.."]]
Inputn=1Output[["Q"]]

1 ≤ n ≤ 9

Try it yourself

Java
class Solution {
    public List<List<String>> solveNQueens(int n) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
One queen per row → fill the board row by row, trying only safe columns. A square's attack lines are its column, row - col and row + col; mark those three and each safety check is O(1).
PatternBacktracking

Instinct Return ALL combinations, permutations, partitions or placements - or ask if any arrangement works - build a candidate step by step and undo each choice.

Memory hack Choose, explore, un-choose - walk the decision tree and snip a branch the moment it can no longer succeed.

Open the Backtracking guide →

Approaches

Brute ForceAll Permutations, then Validate

Time O(n! · n²)Space O(n)

Try every column permutation q (rows/columns can't clash) and keep those with no diagonal pair, i.e. |q[i]-q[j]| == j-i.

Java
public List<List<String>> solveNQueens(int n) {
    List<List<String>> res = new ArrayList<>();
    permute(new int[n], 0, new boolean[n], res);
    return res;
}
private void permute(int[] q, int row, boolean[] used, List<List<String>> res) {
    if (row == q.length) { if (valid(q)) res.add(draw(q)); return; }
    for (int c = 0; c < q.length; c++) {
        if (used[c]) continue;
        used[c] = true; q[row] = c;
        permute(q, row + 1, used, res);
        used[c] = false;
    }
}
private boolean valid(int[] q) {
    for (int i = 0; i < q.length; i++)
        for (int j = i + 1; j < q.length; j++)
            if (Math.abs(q[i] - q[j]) == j - i) return false; // same diagonal
    return true;
}
private List<String> draw(int[] q) {
    List<String> board = new ArrayList<>();
    for (int c : q) board.add(".".repeat(c) + "Q" + ".".repeat(q.length - c - 1));
    return board;
}

Correct but blind: it builds every full permutation before checking diagonals.

At a glance

LevelApproachTimeSpace
Brute ForceAll Permutations, then ValidateO(n! · n²)O(n)
BetterBacktracking + Column/Diagonal ArraysO(n!)O(n²)
OptimalBitmask BacktrackingO(n!)O(n)
Common pitfalls
  • Diagonal index row - col is negative — offset it by n - 1.
  • Forgetting to undo the marks / board cell after the recursive call.
  • Bitmask: not masking with (1 << n) - 1, so shifted bits leak out.
Interview tips
  • Say up front: one queen per row turns 2-D placement into choosing a column per row.
  • Explain the diagonal identities r-c and r+c before coding.
  • Mention the bitmask version as the follow-up optimisation once sets work.
Pattern
Backtracking with constraint sets → place items one slot at a time, prune as soon as a constraint breaks (Sudoku, N-Queens, combinations).
My notes saved in this browser