Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two queens attack each other.
Given an integer n, return all distinct solutions to the n-queens puzzle. You may return the answer in any order.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space, respectively.
Example 1:
Input: n = 4 Output: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above
Example 2:
Input: n = 1 Output: [["Q"]]
Constraints:
1 <= n <= 9Problem summary: The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two queens attack each other. Given an integer n, return all distinct solutions to the n-queens puzzle. You may return the answer in any order. Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space, respectively.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Backtracking
4
1
n-queens-ii)grid-illumination)import java.util.*;
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> ans = new ArrayList<>();
char[][] board = new char[n][n];
for (int r = 0; r < n; r++) Arrays.fill(board[r], '.');
// Columns, main diagonals, anti-diagonals currently occupied by queens.
boolean[] cols = new boolean[n];
boolean[] diag1 = new boolean[2 * n]; // row - col + n
boolean[] diag2 = new boolean[2 * n]; // row + col
backtrack(0, n, board, cols, diag1, diag2, ans);
return ans;
}
private void backtrack(int row, int n, char[][] board, boolean[] cols, boolean[] diag1,
boolean[] diag2, List<List<String>> ans) {
if (row == n) {
List<String> built = new ArrayList<>();
for (char[] r : board) built.add(new String(r));
ans.add(built);
return;
}
for (int col = 0; col < n; col++) {
int d1 = row - col + n;
int d2 = row + col;
if (cols[col] || diag1[d1] || diag2[d2]) continue;
cols[col] = diag1[d1] = diag2[d2] = true;
board[row][col] = 'Q';
backtrack(row + 1, n, board, cols, diag1, diag2, ans);
board[row][col] = '.';
cols[col] = diag1[d1] = diag2[d2] = false;
}
}
}
import "strings"
func solveNQueens(n int) [][]string {
res := [][]string{}
board := make([][]byte, n)
for i := 0; i < n; i++ {
board[i] = []byte(strings.Repeat(".", n))
}
cols := make([]bool, n)
diag1 := make([]bool, 2*n) // row - col + n
diag2 := make([]bool, 2*n) // row + col
var backtrack func(row int)
backtrack = func(row int) {
if row == n {
built := make([]string, n)
for i := 0; i < n; i++ {
built[i] = string(board[i])
}
res = append(res, built)
return
}
for col := 0; col < n; col++ {
d1 := row - col + n
d2 := row + col
if cols[col] || diag1[d1] || diag2[d2] {
continue
}
cols[col], diag1[d1], diag2[d2] = true, true, true
board[row][col] = 'Q'
backtrack(row + 1)
board[row][col] = '.'
cols[col], diag1[d1], diag2[d2] = false, false, false
}
}
backtrack(0)
return res
}
from typing import List
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
ans: List[List[str]] = []
board = [['.'] * n for _ in range(n)]
cols = set()
diag1 = set() # row - col
diag2 = set() # row + col
def backtrack(row: int) -> None:
if row == n:
ans.append([''.join(r) for r in board])
return
for col in range(n):
d1 = row - col
d2 = row + col
if col in cols or d1 in diag1 or d2 in diag2:
continue
cols.add(col)
diag1.add(d1)
diag2.add(d2)
board[row][col] = 'Q'
backtrack(row + 1)
board[row][col] = '.'
cols.remove(col)
diag1.remove(d1)
diag2.remove(d2)
backtrack(0)
return ans
impl Solution {
pub fn solve_n_queens(n: i32) -> Vec<Vec<String>> {
let n = n as usize;
let mut board = vec![vec!['.'; n]; n];
let mut cols = vec![false; n];
let mut diag1 = vec![false; 2 * n]; // row - col + n
let mut diag2 = vec![false; 2 * n]; // row + col
let mut ans = Vec::new();
fn backtrack(
row: usize,
n: usize,
board: &mut Vec<Vec<char>>,
cols: &mut Vec<bool>,
diag1: &mut Vec<bool>,
diag2: &mut Vec<bool>,
ans: &mut Vec<Vec<String>>,
) {
if row == n {
ans.push(board.iter().map(|r| r.iter().collect()).collect());
return;
}
for col in 0..n {
let d1 = row + n - col;
let d2 = row + col;
if cols[col] || diag1[d1] || diag2[d2] {
continue;
}
cols[col] = true;
diag1[d1] = true;
diag2[d2] = true;
board[row][col] = 'Q';
backtrack(row + 1, n, board, cols, diag1, diag2, ans);
board[row][col] = '.';
cols[col] = false;
diag1[d1] = false;
diag2[d2] = false;
}
}
backtrack(0, n, &mut board, &mut cols, &mut diag1, &mut diag2, &mut ans);
ans
}
}
function solveNQueens(n: number): string[][] {
const ans: string[][] = [];
const board: string[][] = Array.from({ length: n }, () => Array(n).fill('.'));
const cols = new Set<number>();
const diag1 = new Set<number>(); // row - col
const diag2 = new Set<number>(); // row + col
const backtrack = (row: number): void => {
if (row === n) {
ans.push(board.map((r) => r.join('')));
return;
}
for (let col = 0; col < n; col++) {
const d1 = row - col;
const d2 = row + col;
if (cols.has(col) || diag1.has(d1) || diag2.has(d2)) continue;
cols.add(col);
diag1.add(d1);
diag2.add(d2);
board[row][col] = 'Q';
backtrack(row + 1);
board[row][col] = '.';
cols.delete(col);
diag1.delete(d1);
diag2.delete(d2);
}
};
backtrack(0);
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Generate every possible combination without any filtering. At each of n positions we choose from up to n options, giving nⁿ total candidates. Each candidate takes O(n) to validate. No pruning means we waste time on clearly invalid partial solutions.
Backtracking explores a decision tree, but prunes branches that violate constraints early. Worst case is still factorial or exponential, but pruning dramatically reduces the constant factor in practice. Space is the recursion depth (usually O(n) for n-level decisions).
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Mutable state leaks between branches.
Usually fails on: Later branches inherit selections from earlier branches.
Fix: Always revert state changes immediately after recursive call.