Problem

Place n queens on an n×n chessboard so no two attack each other. Return all distinct solutions.

Example

Input:  n = 4
Output: 2 solutions: [".Q..","...Q","Q...","..Q."] and ["..Q.","Q...","...Q",".Q.."]

Solution

Backtracking row by row. Track which columns and diagonals are occupied.

def solve_n_queens(n):
    result = []
    cols, d1, d2 = set(), set(), set()
    queens = [-1] * n
    def backtrack(r):
        if r == n:
            result.append(['.' * q + 'Q' + '.' * (n - q - 1) for q in queens])
            return
        for c in range(n):
            if c in cols or (r - c) in d1 or (r + c) in d2: continue
            queens[r] = c
            cols.add(c); d1.add(r - c); d2.add(r + c)
            backtrack(r + 1)
            cols.remove(c); d1.remove(r - c); d2.remove(r + c)
    backtrack(0)
    return result
function solveNQueens(n) {
    const result = [], cols = new Set(), d1 = new Set(), d2 = new Set(), queens = new Array(n);
    function backtrack(r) {
        if (r === n) {
            result.push(queens.map(q => '.'.repeat(q) + 'Q' + '.'.repeat(n - q - 1)));
            return;
        }
        for (let c = 0; c < n; c++) {
            if (cols.has(c) || d1.has(r - c) || d2.has(r + c)) continue;
            queens[r] = c;
            cols.add(c); d1.add(r - c); d2.add(r + c);
            backtrack(r + 1);
            cols.delete(c); d1.delete(r - c); d2.delete(r + c);
        }
    }
    backtrack(0);
    return result;
}
void backtrack(int r, int n, vector<int>& queens, set<int>& cols, set<int>& d1, set<int>& d2, vector<vector<string>>& result) {
    if (r == n) {
        vector<string> board;
        for (int q : queens) {
            string row(n, '.');
            row[q] = 'Q';
            board.push_back(row);
        }
        result.push_back(board);
        return;
    }
    for (int c = 0; c < n; c++) {
        if (cols.count(c) || d1.count(r - c) || d2.count(r + c)) continue;
        queens[r] = c;
        cols.insert(c); d1.insert(r - c); d2.insert(r + c);
        backtrack(r + 1, n, queens, cols, d1, d2, result);
        cols.erase(c); d1.erase(r - c); d2.erase(r + c);
    }
}
vector<vector<string>> solveNQueens(int n) {
    vector<vector<string>> result;
    vector<int> queens(n);
    set<int> cols, d1, d2;
    backtrack(0, n, queens, cols, d1, d2, result);
    return result;
}
public List<List<String>> solveNQueens(int n) {
    List<List<String>> result = new ArrayList<>();
    int[] queens = new int[n];
    Set<Integer> cols = new HashSet<>(), d1 = new HashSet<>(), d2 = new HashSet<>();
    backtrack(0, n, queens, cols, d1, d2, result);
    return result;
}
private void backtrack(int r, int n, int[] queens, Set<Integer> cols, Set<Integer> d1, Set<Integer> d2, List<List<String>> result) {
    if (r == n) {
        List<String> board = new ArrayList<>();
        for (int q : queens) {
            char[] row = new char[n];
            Arrays.fill(row, '.');
            row[q] = 'Q';
            board.add(new String(row));
        }
        result.add(board);
        return;
    }
    for (int c = 0; c < n; c++) {
        if (cols.contains(c) || d1.contains(r - c) || d2.contains(r + c)) continue;
        queens[r] = c;
        cols.add(c); d1.add(r - c); d2.add(r + c);
        backtrack(r + 1, n, queens, cols, d1, d2, result);
        cols.remove(c); d1.remove(r - c); d2.remove(r + c);
    }
}

Complexity

  • Time: O(n!)
  • Space: O(n)

Explanation

A diagonal where r – c is constant is the same diagonal. Same for anti-diagonal where r + c is constant. Tracking these in sets gives O(1) attack-check.

Share this article

Comments

Join the discussion. Got a question, found an issue, or want to share your experience?

Leave a Comment

Your email stays private. We just use it for replies.

Nothing to preview yet.

Use **bold**, *italic*, `code`, ```code blocks```, [link](url), > quote, - list