Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Data Structures & Algorithms (DSA)  Module 4 – Recursion and backtracking

N-Queens problem and Sudoku: constraint search

The N-Queens problem and Sudoku stated with limits and examples, a brute force timed on both, and the signals that turn them into a constraint search.

  • Advanced
  • 40 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free intro, Pro: 9 of 40 minutes free
Free: The problem: n queens, and a 9 × 9 grid · The brute force, and why it fails at these sizes · What to notice. With a pass: the other 12 sections and 3 interview answers, about 31 minutes.

What you will learn

  • Solve the N-Queens problem with constant-time checks on columns and both diagonals
  • Optimise the queens search with bitmasks and the mirror image, and measure the gain
  • Write a Sudoku solver that fills the most constrained cell first and fills forced digits before guessing
  • Construct a placement of n queens without search when n shares no factor with 6, and prove the rule
  • Compare search strategies by the number of calls each one makes

Before you start

What you’ll learn · Before you start

What you will learn

  • Solve the N-Queens problem with constant-time checks on columns and both diagonals
  • Optimise the queens search with bitmasks and the mirror image, and measure the gain
  • Write a Sudoku solver that fills the most constrained cell first and fills forced digits before guessing
  • Construct a placement of n queens without search when n shares no factor with 6, and prove the rule
  • Compare search strategies by the number of calls each one makes

Before you start

On this page

The N-Queens problem asks for every way to place n queens on an n × n chessboard so that no two attack each other. Two queens attack when they share a row, a column or a diagonal. Sudoku asks for the digits 1 to 9 in every row, column and 3 × 3 box of a 9 × 9 grid. Both yield to constraint search, a form of backtracking that places one piece at a time, checks only the rules that piece touches, and backs out the moment one breaks.

The problem: n queens, and a 9 × 9 grid

Problem A: n queens

Write count_queens(n), the number of placements of n queens on an n × n board, and solve_queens(n), which lists them, each as the columns of the queens in rows 0 to n − 1. Limits: 1 ≤ n ≤ 12 for counting, n ≤ 10 for listing.

For n = 4 there are two placements, columns [1, 3, 0, 2] and [2, 0, 3, 1]. Boards of size 2 and 3 have no placement at all, and size 1 has one. For n = 8 the N-Queens problem has 92 placements, the count the OEIS lists.

Problem B: a 9 × 9 puzzle

Write solve_sudoku(grid), which fills the empty cells (stored as 0) and returns True, or returns False and leaves the grid as it was when no completion exists.

The example puzzle has 25 given digits and exactly one solution. A 2 written into its empty cell at row 7, column 8 breaks no rule yet, but leaves a grid that no Sudoku solver can complete.

The two placements of four queens on a 4 × 4 board, and the example 9 × 9 puzzle with its 25 given digits.A: the two placements for n = 4QQQQcolumns 1, 3, 0, 2QQQQcolumns 2, 0, 3, 1Rows are numbered 0 to 3 from the top,columns 0 to 3 from the left. Each boardis the mirror image of the other.B: the example puzzle, 25 digits given4831589731915516933756428Thick lines mark the nine 3 x 3 boxes.

The two problems on their examples

Text description of the diagram

Part A shows the only two placements of four queens on a 4 × 4 board, with rows numbered 0 to 3 from the top and columns 0 to 3 from the left. In the first placement the queens of rows 0, 1, 2 and 3 stand in columns 1, 3, 0 and 2. In the second they stand in columns 2, 0, 3 and 1. In both, no two queens share a row, a column or a diagonal, and each placement is the mirror image of the other.

Part B shows the example puzzle, a 9 × 9 grid divided into nine 3 × 3 boxes by thick lines. Reading row by row, with columns numbered 0 to 8:

  • Row 0: 4 in column 2, 8 in column 5, 3 in column 7.
  • Row 1: 1 in column 4, 5 in column 8.
  • Row 2: 8 in column 6, 9 in column 8.
  • Row 3: 7 in column 2, 3 in column 3, 1 in column 7.
  • Row 4: 9 in column 1, 1 in column 5, 5 in column 7.
  • Row 5: 5 in column 0, 1 in column 1, 6 in column 5, 9 in column 6, 3 in column 8.
  • Row 6: 3 in column 0, 7 in column 8.
  • Row 7: 5 in column 4.
  • Row 8: 6 in column 1, 4 in column 4, 2 in column 5, 8 in column 7.

That is 25 given digits and 56 empty cells.

The brute force, and why it fails at these sizes

Every ordering of the columns puts one queen in each row and each column, so the brute force tries them all and checks the diagonals of each finished board. For the grid, it tries every digit in every empty cell.

Finished boards first, diagonals checked last Python · brute/brute_force.py
"""The brute force for both puzzles: build complete answers first, check the rules last."""
import time
from itertools import permutations
from math import factorial


def queens_brute_force(n):
    """Every ordering of the columns puts one queen in each row and each column; keep those with no shared diagonal."""
    found = 0
    for cols in permutations(range(n)):
        if len({r - c for r, c in enumerate(cols)}) == n and len({r + c for r, c in enumerate(cols)}) == n:
            found += 1
    return found


print(" n  placements  orderings tried   time")
for n in range(4, 10):
    start = time.perf_counter()
    found = queens_brute_force(n)
    seconds = time.perf_counter() - start
    print(f"{n:2} {found:11,} {factorial(n):16,} {seconds:6.2f} s")
rate = factorial(9) / seconds
print(f"n = 12: {factorial(12):,} orderings, about {factorial(12) / rate / 60:.0f} minutes at the speed of the last row")

PUZZLE = "004008030000010005000000809007300010090001050510006903300000007000050000060042080"
empty = PUZZLE.count("0")
print(f"the 9 x 9 puzzle has {empty} empty cells: 9 ** {empty} = {9 ** empty:.2e} ways to fill them")

Output

 n  placements  orderings tried   time
 4           2               24   0.00 s
 5          10              120   0.00 s
 6           4              720   0.00 s
 7          40            5,040   0.00 s
 8          92           40,320   0.03 s
 9         352          362,880   0.24 s
n = 12: 479,001,600 orderings, about 5 minutes at the speed of the last row
the 9 x 9 puzzle has 56 empty cells: 9 ** 56 = 2.74e+53 ways to fill them

This output changes from run to run: the times depend on the computer and on what else it is doing

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 brute_force.py

The counts are right, but the cost is n!: 479,001,600 boards for n = 12, minutes of Python for one answer. Any n of the n² squares would be worse still, 4,426,165,368 boards for n = 8, and the grid’s 56 empty cells allow about 2.7 × 10⁵³ fillings.

What to notice

  • A conflict always involves exactly two pieces, so it shows the moment the second of them lands.
  • No row can hold two queens, and there are as many rows as queens: fill the rows one at a time.
  • A cell’s row, column and box decide which digits it can still take.
  • A cell with one possible digit is forced, and one with none is lost, so handle such cells first.

Six techniques follow:

  • Sets of used columns and diagonals make the test of a square three lookups.
  • Bitmasks give all safe squares of a row from one expression.
  • Mirror symmetry lets a counter explore only half of the first row.
  • Most constrained first fills the cell with the fewest possible digits next.
  • Forced digits are written in before any guess.
  • A modular rule places n queens with no search when n shares no factor with 6.

Queens row by row, with constant-time conflict checks Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • Why r − c and r + c name the diagonals, and why each placement is counted once
  • Bitmasks and the mirror image, timed
  • Sudoku with candidate masks: most constrained first, then forced digits
  • One placement for any n that shares no factor with 6
  • The code in five languages
  • How much work it does
  • Edge cases and common bugs
  • Variants and follow-up questions
  • Exercise: count the placements of n queens
    • Count the placements of n queens
  • Check yourself
  • Interview questions
    • Why can an N-Queens search place exactly one queen in each row, and what does that do to the size of the search?
    • In an N-Queens search, how do you test in constant time whether a square is attacked along a diagonal by a queen already placed? Prove that your test is exact, and say how it changes with bitmasks.
    • A Sudoku solver fills cells in reading order and solves most puzzles at once, but a few take seconds, and on one puzzle with no solution it seems to run for ever. What do you change, and how do you show that the change helps?
    • A service must return one valid placement of n queens for any n up to 1,000,000 within a second. A backtracking search for the first placement is quick for small n, but its work jumps unpredictably as n grows. What do you do?
  • Key takeaways

9 runnable examples (C++, Go, Java, JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 25 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.