算法设计:
回溯算法:
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
res = []
s = "." * n
def backtrack(i, tmp,col,z_diagonal,f_diagonal):
if i == n:
res.append(tmp)
return
for j in range(n):
if j not in col and i + j not in z_diagonal and i - j not in f_diagonal:
backtrack(i+1,tmp + [s[:j] + "Q" + s[j+1:]], col | {j}, z_diagonal |{i + j} , f_diagonal |{i - j} )
backtrack(0,[],set(),set(),set())
return res
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
def traceBack(r):
#得到一个合理结果
if r >= n:
temp = []
for i in matrix:
temp.append(''.join(i))
result.append(temp)
return
#只需对此行的各列进行分析
for i in range(n):
if col[i] and hill_dig[r + i] and dale_dig[r - i + n - 1]:
matrix[r][i] = 'Q'
#束缚条件
col[i] = False
hill_dig[r+i] = False
dale_dig[r-i+n-1] = False
#对下一行进行分析
traceBack(r + 1)
#回退,束缚条件重置
matrix[r][i] = '.'
col[i] = True
hill_dig[r + i] = True
dale_dig[r - i + n - 1] = True
return
result = []
matrix = [['.' for i in range(n)] for i in range(n)]
col = [True for i in range(n)]
dale_dig = [True for i in range(2 * n - 1)] #主对角线 row-col常数
hill_dig = [True for i in range(2 * n - 1)] #从对角线,row+col常数
traceBack(0)
return result
class Solution(object):
def solveNQueens(self, n):
def DFS(queens, xy_dif, xy_sum):
p = len(queens)
if p == n:
result.append(queens)
return None
for q in range(n):
if q not in queens and p-q not in xy_dif and p+q not in xy_sum:
DFS(queens+[q], xy_dif+[p-q], xy_sum+[p+q])
result = []
DFS([], [], [])
return [ ["."*i + "Q" + "."*(n-i-1) for i in sol] for sol in result ]
算法设计:
回溯算法
class Solution:
def totalNQueens(self, n: int) -> int:
self.res = 0
def backtrack(i,col,z_diagonal,f_diagonal):
if i == n:return True
for j in range(n):
if j not in col and i + j not in z_diagonal and i - j not in f_diagonal:
if backtrack(i+1, col | {j}, z_diagonal |{i + j} , f_diagonal |{i - j} ) :
self.res += 1
return False
backtrack(0,set(),set(),set())
return self.res
class Solution:
def totalNQueens(self, n: int) -> int:
def DFS(n: int, row: int, cols: int, left: int, right: int):
""" 深度优先搜索
:param n: N皇后个数
:param row: 递归的深度
:param cols: 可被攻击的列
:param left: 左侧斜线上可被攻击的列
:param right: 右侧斜线上可被攻击的列
"""
if row >= n:
self.res += 1
return
# 获取当前可用的空间
bits = (~(cols | left | right)) & ((1 << n) - 1)
# 遍历可用空间
while bits:
# 获取一个位置
p = bits & -bits
DFS(n, row + 1, cols | p, (left | p) << 1, (right | p) >> 1)
bits = bits & (bits - 1)
if not (n == 1 or n >= 4):
# N皇后问题只有在 N 大于等于 4 或等于 1 的时候才有解
return 0
self.res = 0
DFS(n, 0, 0, 0, 0)
return self.res
使用 bitmap 回溯
class Solution:
def totalNQueens(self, n):
"""
:type n: int
:rtype: int
"""
def backtrack(row = 0, hills = 0, next_row = 0, dales = 0, count = 0):
"""
:type row: 当前放置皇后的行号
:type hills: 主对角线占据情况 [1 = 被占据,0 = 未被占据]
:type next_row: 下一行被占据的情况 [1 = 被占据,0 = 未被占据]
:type dales: 次对角线占据情况 [1 = 被占据,0 = 未被占据]
:rtype: 所有可行解的个数
"""
if row == n: # 如果已经放置了 n 个皇后
count += 1 # 累加可行解
else:
# 当前行可用的列
# ! 表示 0 和 1 的含义对于变量 hills, next_row and dales的含义是相反的
# [1 = 未被占据,0 = 被占据]
free_columns = columns & ~(hills | next_row | dales)
# 找到可以放置下一个皇后的列
while free_columns:
# free_columns 的第一个为 '1' 的位
# 在该列我们放置当前皇后
curr_column = - free_columns & free_columns
# 放置皇后
# 并且排除对应的列
free_columns ^= curr_column
count = backtrack(row + 1,
(hills | curr_column) << 1,
next_row | curr_column,
(dales | curr_column) >> 1,
count)
return count
# 棋盘所有的列都可放置,
# 即,按位表示为 n 个 '1'
# bin(cols) = 0b1111 (n = 4), bin(cols) = 0b111 (n = 3)
# [1 = 可放置]
columns = (1 << n) - 1
return backtrack()