题解:
对于本题,我们首先创建一个棋盘,利用数组实现:
def solveNQueens(self, n):
grid = [['.'] * n for i in range(n)]#创建棋盘
queen = set()#存储皇后的位置索引
output = []#存储最后的结果
self.queenDFS(grid, 0, n,queen,output)
return output
本题利用回溯算法解决。
对于本题,关键点有三个,一个是回溯算法的递归(撤销);一个是判断放置位置是否合法;找到所有的可行解。(即找到所有的全排列)
对于第一个关键点:
首先看labuladong大神准备的回溯算法模版:
def backtrack(...):
for 选择 in 选择列表:
做选择
backtrack(...)
撤销选择
对于这个撤销操作,存在两种可能:
- 即在选择当前位置之后,如果当前位置不满足条件,需要撤销选择,即回溯的过程,就像一棵二叉树,走到一个结点的子结点后,再退回到父结点。
- 再找到当前一组解后的撤销操作,即把所有变量变换回初始的状态,为开始下一轮的遍历做准备;
代码如下:
def queenDFS(self,grid,index,n,queen,output):
if index == n:
solution = []
for _, col in sorted(queen):
solution.append('.' * col + 'Q' + '.' * (n-col-1))
output.append(solution)
for i in range(n):
if(self.isQueenOk(grid,index,i)):
# print("####")
queen.add((index,i))#进行选择
grid[index][i] = 'Q'#进行选择
self.queenDFS(grid, index + 1, n,queen,output)
grid[index][i] = '.'#进行撤销
queen.remove((index,i))#进行撤销
判断放置的位置是否合法
因为是按行索引,所以我们只需要判断列,主对角线,副对角线是否符合要求。
其中主对角线位置等于当前位置的行减一,列减一。副对角线位置等于当前位置的行减一,列加一。
代码如下:
def isQueenOk(self,grid,row,col):
#纵向合法性校验
for i in range(row):
if grid[i][col] == 'Q':
return False
#主对角线合法性校验
x = row - 1
y = col - 1
while x >= 0 and y >= 0:
if grid[x][y] == 'Q':
return False
x -= 1
y -= 1
#副对角线合法性校验
x = row - 1
y = col + 1
while x >= 0 and y < len(grid[0]):
if grid[x][y] == 'Q':
return False
x -= 1
y += 1
return True
总体代码如下:
class Solution:
def solveNQueens(self, n):
grid = [['.'] * n for i in range(n)]
queen = set()
output = []
# print(grid)
self.queenDFS(grid, 0, n,queen,output)
return output
def isQueenOk(self,grid,row,col):
#纵向合法性校验
for i in range(row):
if grid[i][col] == 'Q':
return False
#主对角线合法性校验
x = row - 1
y = col - 1
while x >= 0 and y >= 0:
if grid[x][y] == 'Q':
return False
x -= 1
y -= 1
#副对角线合法性校验
x = row - 1
y = col + 1
while x >= 0 and y < len(grid[0]):
if grid[x][y] == 'Q':
return False
x -= 1
y += 1
return True
def queenDFS(self,grid,index,n,queen,output):
if index == n:
solution = []
for _, col in sorted(queen):
solution.append('.' * col + 'Q' + '.' * (n-col-1))
output.append(solution)
for i in range(n):
if(self.isQueenOk(grid,index,i)):
# print("####")
queen.add((index,i))
grid[index][i] = 'Q'
self.queenDFS(grid, index + 1, n,queen,output)
grid[index][i] = '.'
queen.remove((index,i))
总结:
认为本题的关键在于回溯算法的撤销操作,以及四个方向的判断;认真理解回溯算法即可很好的求解本题。
本题是找到所有的可行解,如果是找到一组可行解,再找到之后直接进行return即可,不用进行后面的遍历。
参考:
https://leetcode-cn.com/problems/n-queens/solution/hui-su-suan-fa-xiang-jie-by-labuladong/
https://juejin.im/post/5accdb236fb9a028bb195562
https://www.jianshu.com/p/bb123944d3e5