N-Queens: Classic Constraint Satisfaction Backtracking

Sanjeev SharmaSanjeev Sharma
3 min read

Advertisement

N-Queens Problem

Place n queens on n×n board so no two queens attack each other.

Python Implementation

def solveNQueens(n):
    result = []
    cols = set()
    diag1 = set()   # row - col (top-left to bottom-right)
    diag2 = set()   # row + col (top-right to bottom-left)
    board = [['.' ] * n for _ in range(n)]

    def bt(row):
        if row == n:
            result.append([''.join(r) for r in board])
            return
        for col in range(n):
            if col in cols or (row-col) in diag1 or (row+col) in diag2:
                continue
            board[row][col] = 'Q'
            cols.add(col); diag1.add(row-col); diag2.add(row+col)
            bt(row + 1)
            board[row][col] = '.'
            cols.discard(col); diag1.discard(row-col); diag2.discard(row+col)

    bt(0)
    return result

def totalNQueens(n):
    count = [0]
    cols = set(); d1 = set(); d2 = set()
    def bt(row):
        if row == n: count[0] += 1; return
        for col in range(n):
            if col in cols or (row-col) in d1 or (row+col) in d2: continue
            cols.add(col); d1.add(row-col); d2.add(row+col)
            bt(row + 1)
            cols.discard(col); d1.discard(row-col); d2.discard(row+col)
    bt(0)
    return count[0]

print(totalNQueens(8))  # 92

C++ Implementation (Bitmask N-Queens — fastest)

#include <bits/stdc++.h>
using namespace std;

int totalNQueens(int n) {
    int count = 0;
    // cols, diag1, diag2 as bitmasks
    function<void(int, int, int, int)> bt = [&](int row, int cols, int d1, int d2) {
        if (row == n) { count++; return; }
        int available = ((1 << n) - 1) & ~(cols | d1 | d2);
        while (available) {
            int bit = available & (-available);  // lowest set bit
            available &= available - 1;
            bt(row + 1, cols | bit, (d1 | bit) << 1, (d2 | bit) >> 1);
        }
    };
    bt(0, 0, 0, 0);
    return count;
}

vector<vector<string>> solveNQueens(int n) {
    vector<vector<string>> result;
    vector<int> queens(n, -1); // queens[row] = col
    set<int> cols, d1, d2;

    function<void(int)> bt = [&](int row) {
        if (row == n) {
            vector<string> board(n, string(n, '.'));
            for (int r = 0; r < n; r++) board[r][queens[r]] = 'Q';
            result.push_back(board);
            return;
        }
        for (int col = 0; col < n; col++) {
            if (cols.count(col) || d1.count(row-col) || d2.count(row+col)) continue;
            queens[row] = col;
            cols.insert(col); d1.insert(row-col); d2.insert(row+col);
            bt(row + 1);
            cols.erase(col); d1.erase(row-col); d2.erase(row+col);
        }
    };
    bt(0);
    return result;
}

Java Implementation

import java.util.*;

public class NQueens {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> result = new ArrayList<>();
        int[] queens = new int[n];
        Arrays.fill(queens, -1);
        Set<Integer> cols = new HashSet<>(), d1 = new HashSet<>(), d2 = new HashSet<>();
        backtrack(n, 0, queens, cols, d1, d2, result);
        return result;
    }

    void backtrack(int n, int row, int[] queens, Set<Integer> cols,
                   Set<Integer> d1, Set<Integer> d2, List<List<String>> result) {
        if (row == n) {
            List<String> board = new ArrayList<>();
            for (int r = 0; r < n; r++) {
                char[] line = new char[n];
                Arrays.fill(line, '.');
                line[queens[r]] = 'Q';
                board.add(new String(line));
            }
            result.add(board);
            return;
        }
        for (int col = 0; col < n; col++) {
            if (cols.contains(col) || d1.contains(row-col) || d2.contains(row+col)) continue;
            queens[row] = col;
            cols.add(col); d1.add(row-col); d2.add(row+col);
            backtrack(n, row+1, queens, cols, d1, d2, result);
            cols.remove(col); d1.remove(row-col); d2.remove(row+col);
        }
    }
}

Complexity

  • Time: O(n!) with pruning significantly reduces actual calls
  • Space: O(n) for recursion and tracking sets

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro