# Leetcode 51. N-Queens ## 題解 ### DFS Back Tracking 如果要知道 n * n 種棋盤組合,我們需要窮舉 n ** n 種組合,才會得到答案,但是 N 皇后問題中,每個皇后橫向、縱向、斜向都不能重複,所以我們可以假設每一行都只會有一個皇后,每一列也都只會有一格皇后,由此可以推導出這個問題的簡化版本 [Permutations](https://hackmd.io/@paxton0222/SyHyDV_l3),可以假設 4 x 4 棋盤上的皇后 "Q..." 為 1, ".Q.." 為 2,以此類推,所以可能的皇后組合就會變成 [1,2,3,4] 的所有不重複排列組合,剩下的只需要去驗證,斜向排列的組合是否合法即可 ```python! class Solution: def solveNQueens(self, n: int) -> List[List[str]]: pos = [("." * i) + "Q" + "." * (n - i-1) for i in range(n)] # 先生成 n 種排列組合 output = [] path = set() directions = [[-1,-1], [-1,1]] # left top, right top 這邊只需要向上斜巷驗證 def vaild(x: int,y: int, board: List[List[str]]) -> bool: if y == 0: # 第一行不需要驗證 return True for i in range(y): for _y,_x in directions: new_x = x + (_x*(i+1)) new_y = y + (_y*(i+1)) if 0 <= new_y < n and 0 <= new_x < n: if board[new_y][new_x] == "Q": # 如果斜向路徑上有皇后,代表組合不合法 return False return True # 所有路徑上都沒有皇后,目前組合合法 def dfs(board: List[List[str]]): if len(board) == n: output.append(list(board)) else: for i in range(n): if i not in path: board.append(pos[i]) path.add(i) if vaild(i,len(board) - 1,board): # 合法就繼續找下去,不合法剪枝 dfs(board) board.pop() path.remove(i) dfs([]) return output ``` ### 斜向檢查優化 ![y-x](https://hackmd.io/_uploads/SyoLpwTRh.png) ![y+x](https://hackmd.io/_uploads/HJldTPaCn.png) ```python! class Solution: def solveNQueens(self, n: int) -> List[List[str]]: # Time complexity: O(N!) # Space complexity: O(N) pos = [("." * i) + "Q" + "." * (n - i-1) for i in range(n)] output = [] path = set() nd = set() pd = set() def dfs(board: List[List[str]]): if len(board) == n: output.append(list(board)) else: for x in range(n): y = len(board) rmc = y - x # y - x 負向斜線 rpc = y + x # y + x 正向斜線 if x not in path and rmc not in nd and rpc not in pd: board.append(pos[x]) path.add(x) nd.add(rmc) pd.add(rpc) dfs(board) pd.remove(rpc) nd.remove(rmc) path.remove(x) board.pop() dfs([]) return output ```