↓Skip to main content
  1. LeetCode/

LeetCode 51: N-Queens

·2 mins· ·
LeetCode Hard Backtracking
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: hard First Attempt: 2026-07-08

  • Submissions: Accepted → Accepted (retyped once)

Approach
#

Each row holds exactly one queen, so decide the column row by row. Before placing, check three things:

ConflictCheck
Same columncol is already used
Same “/” diagonalsame row + col
Same “" diagonalsame row - col

Three sets track them, so each check is O(1).

My Solution
#

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        res = []
        board = [["."] * n for _ in range(n)]
        cols, diag1, diag2 = set(), set(), set()

        def backtrack(row: int) -> None:
            if row == n:
                res.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)

                backtrack(row + 1)

                board[row][col] = "."
                cols.remove(col)
                diag1.remove(row + col)
                diag2.remove(row - col)

        backtrack(0)
        return res

My original code had ["".join(row) for row in board], where the comprehension’s row shared its name with the parameter row. Python 3 comprehensions have their own scope, so it worked, but it is easy to misread; here it is r.

Complexity
#

Time O(n!): n choices for the first row, at most n - 1 for the second, and so on; pruning cuts this down a lot in practice. Space O(n^2) for the board.

Mistakes to Avoid
#

  • Mixing up the diagonals: “/” is row + col, “" is row - col.
  • Forgetting one of the sets when undoing.
  • Storing board itself as an answer: convert it to strings, or later changes overwrite stored answers.

Interview Explanation
#

Each row has exactly one queen, so I backtrack row by row over the column choice. Three sets track used columns and the row + col and row - col diagonals, and conflicts are skipped. After placing a queen I recurse into the next row and restore the sets and board on return. At row n, I store the board as strings.

Related

LeetCode 1402: Reducing Dishes
·2 mins
LeetCode Hard Dynamic-Programming Greedy Sorting Array
LeetCode 1402 note: sort and take dishes from most satisfying down; each new dish goes first and shifts the chosen ones one slot later, adding the current chosen sum, so keep going while that sum is positive
LeetCode 552: Student Attendance Record II
·2 mins
LeetCode Hard Dynamic-Programming State-Machine
LeetCode 552 note: state machine DP with state “A used × trailing L run”, 6 states; each day’s P, A or L picks the next state
LeetCode 757: Set Intersection Size At Least Two
·2 mins
LeetCode Hard Greedy Sorting
LeetCode 757 note: sort by right end (larger left end first on ties) and track only the two rightmost points; add the two right-end points when uncovered, or the right end when only one is covered
LeetCode 1526: Minimum Number of Increments on Subarrays to Form a Target Array
·1 min
LeetCode Hard Dynamic-Programming Greedy Monotonic-Stack Array
LeetCode 1526 note: scanning left to right, every rise above the previous height needs that many new operations; drops reuse earlier operations
LeetCode 1147: Longest Chunked Palindrome Decomposition
·2 mins
LeetCode Hard Dynamic-Programming Greedy Two-Pointers Rolling-Hash String
LeetCode 1147 note: build strings inward from both ends and cut a pair as soon as they match; cutting early is best, and any leftover middle counts as one chunk
LeetCode 3651: Minimum Cost Path with Teleportations
·2 mins
LeetCode Hard Dynamic-Programming Grid-Dp Matrix Array
LeetCode 3651 note: compute layer by layer over teleports; arriving at a cell by teleport costs the previous layer’s minimum over cells with value >= it, found with a running minimum after sorting, followed by the usual right / down grid DP