题目:N queens
将n个皇后放在n*n的棋盘上,任何两个皇后都不能攻击到对方
思路分析一:递归
N行N列的表格,每行有N列个单元格可以摆放"皇后",每将“皇后”摆放在一列,就看下一行是否可以继续摆放,直到不满足条件回溯,或者最终摆放成功,产生一个成功摆放方案。
可行性剪枝
用三个数组分别记录之前已成功摆好的"皇后"们的列位置、行列之和、行列之差。
如果当前摆放"皇后"所在列已有,或行列之和已有,或行列之差已有,则代表与之前的皇后在同一行、或同一斜线上,即不满足条件停止递归
递归截止条件
当将所有行都摆放完皇后后,即代表一次成功的摆放
代码
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
def DFS(queens, xy_subb, xy_sum):
y_row = len(queens)
if y_row == n:
result.append(queens)
return None
for x_col in range(n):
su, sm = y_row - x_col, y_row + x_col
if x_col not in queens and su not in xy_subb and sm not in xy_sum:
DFS(queens+[x_col], xy_subb+[su], xy_sum+[sm])
result = []
DFS([], [], [])
return [['.'*i + 'Q' + '.'*(n-i-1) for i in queens] for queens in result]
时间复杂度为指数级别,空间复杂度也为指数级
思路分析二:递归+生成器
逐行摆放皇后,如果最终能在最后一行摆放成功,则代表这是一个成功的摆放方案,则生成器生成当前的“皇后”的摆放情况,并逐层回溯组合程完整的摆放方案,
可行性剪枝
将当前要摆放的“皇后”行、列位置与之前已经摆好的皇后位置做比较,如果列差为0(代表同一列)或者列差和行差绝对值相等(代表在同一斜线上),即方案不可行,停止递归
递归截止条件
能成功将最后一个皇后摆放到最后一行
代码
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
def DFS(queens=()):
def conflict():
y_row = len(queens)
for row in range(y_row):
if abs(queens[row] - x_col) in (0, y_row - row):
return True
return False
for x_col in range(n):
if not conflict():
if len(queens) == n - 1:
yield (x_col,)
else:
for result in DFS(queens+(x_col,)):
yield (x_col,) + result
return [['.'*i + 'Q' + '.'*(n-i-1) for i in queens] for queens in DFS()]
该方案比思路一运行要慢,因为是通过计算来判断是否满足摆放条件的;但空间复杂度方面则有优势,每个位置都少用两个列表,而且使用了生成器而不是列表