↓快轉到主要內容
  1. LeetCode/

LeetCode 51: N-Queens

·1 分鐘· ·
LeetCode Hard Backtracking
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: hard 第一次嘗試:2026-07-08

  • 提交紀錄:Accepted → Accepted(重打一次)

解題思路
#

每一列剛好放一個皇后,所以逐列決定皇后放在哪一欄。放之前檢查三件事:

衝突判斷方式
同一欄col 已經被用過
同一條「/」對角線row + col 相同
同一條「\」對角線row - col 相同

用三個 set 分別記錄,檢查都是 O(1)。

我的解法
#

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

原本寫的是 ["".join(row) for row in board],推導式裡的 row 跟函式參數 row 同名。Python 3 的推導式有自己的作用域,所以沒出錯,但讀的時候容易搞混,這裡改成 r。

複雜度
#

時間 O(n!):第一列有 n 種選擇,第二列最多 n - 1 種……加上剪枝,實際上少很多。空間 O(n^2),存棋盤。

要特別避免的錯誤
#

  • 對角線的判斷寫錯:「/」是 row + col、「\」是 row - col。
  • 撤銷時漏掉其中一個 set。
  • 存答案時直接存 board:要轉成字串,不然之後的修改會改到已經存的答案。

面試口說整理
#

每一列剛好一個皇后,所以我逐列回溯,決定皇后放在哪一欄。用三個 set 記錄被佔用的欄、row + col 和 row - col 兩種對角線,衝突就跳過。放下之後遞迴下一列,回來時把三個 set 和棋盤都還原。到第 n 列時把棋盤轉成字串存下來。

相關文章

LeetCode 1402: Reducing Dishes
·1 分鐘
LeetCode Hard Dynamic-Programming Greedy Sorting Array
LeetCode 1402 解題筆記:排序後從滿意度大的開始選;每多選一道放在最前面,前面選的都往後一格,總和增加「目前選的滿意度總和」,總和是正的就繼續選
LeetCode 552: Student Attendance Record II
·2 分鐘
LeetCode Hard Dynamic-Programming State-Machine
LeetCode 552 解題筆記:狀態機 DP,狀態是「A 用了幾次 × 結尾連續幾個 L」共 6 種;每天選 P、A、L 決定下一個狀態
LeetCode 757: Set Intersection Size At Least Two
·1 分鐘
LeetCode Hard Greedy Sorting
LeetCode 757 解題筆記:按右端點排序(同右端點時左端點大的先),只記最右邊兩個點;沒蓋到就放右端兩點,只蓋到一個就補右端點
LeetCode 1526: Minimum Number of Increments on Subarrays to Form a Target Array
·1 分鐘
LeetCode Hard Dynamic-Programming Greedy Monotonic-Stack Array
LeetCode 1526 解題筆記:從左往右看,每次比前一個高,多出來的高度都要新開那麼多次操作;變矮的部分可以沿用之前的操作
LeetCode 1147: Longest Chunked Palindrome Decomposition
·1 分鐘
LeetCode Hard Dynamic-Programming Greedy Two-Pointers Rolling-Hash String
LeetCode 1147 解題筆記:從兩端同時往內累積字串,左右一相等就切成一對;越早切越好,剩下的中間(如果有)算一塊
LeetCode 3651: Minimum Cost Path with Teleportations
·2 分鐘
LeetCode Hard Dynamic-Programming Grid-Dp Matrix Array
LeetCode 3651 解題筆記:一層一層算傳送次數;傳送到某格的成本是上一層「值 >= 它的格子」的最小值,排序後用前綴最小值求,再跑一次右 / 下的 Grid DP