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.
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 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.
"""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.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
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
- NIST Dictionary of Algorithms and Data Structures: n queens (National Institute of Standards and Technology (NIST))
- NIST Dictionary of Algorithms and Data Structures: backtracking (National Institute of Standards and Technology (NIST))
- A000170: Number of ways of placing n nonattacking queens on an n X n board (The On-Line Encyclopedia of Integer Sequences (OEIS Foundation))
- A002562: Number of ways of placing n nonattacking queens on n X n board (symmetric solutions count only once) (The On-Line Encyclopedia of Integer Sequences (OEIS Foundation))
- A survey of known results and research areas for n-queens (J. Bell and B. Stevens, Discrete Mathematics 309(1), 2009) (Elsevier)
- ACM/IEEE-CS/AAAI Computer Science Curricula 2023: Algorithmic Foundations (AL) (ACM, IEEE Computer Society and AAAI)
- itertools.permutations (The Python Standard Library) (Python Software Foundation)
- Bitwise operations on integer types, and int.bit_count() (The Python Standard Library) (Python Software Foundation)
- Math.clz32() (MDN Web Docs)
- Java SE 25 API: java.lang.Integer (bitCount, lowestOneBit, numberOfTrailingZeros) (Oracle)
- std::popcount (cppreference.com) (cppreference.com)
- std::countr_zero (cppreference.com) (cppreference.com)
- Package bits (math/bits): OnesCount, TrailingZeros (The Go Authors)
- The Go Programming Language Specification: arithmetic operators (&^, bit clear) (The Go Authors)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress