题目介绍:51. N皇后
先给出答案:
class Solution(object):
def solveNQueens(self, n):
"""
:type n: int
:rtype: List[List[str]]
使用最基础的回溯算法,决策树遍历
"""
import copy
if n == 0: return []
res = []
path = [['.' for _ in range(n)] for _ in range(n)] # 申请列表类型变量,因为python字符串不能直接修改某个字符
direction = [[-1, -1, -1, 0, 0, 1, 1, 1],
[-1, 0 ,1, -1, 1, -1, 0, 1]] # 分别表示上下左右 左上 左下 右上 右下
# 判断当前位置是否合法,此处可以优化,因为当前元素上方、左下角和右上角的元素不需要判断
def can(i, j):
for biger in range(1, n+1): # 一层一层向8个方向扩展,像泛起的水花
for k in range(8):
nexti = i + direction[0][k]*biger
nextj = j + direction[1][k]*biger
if nexti >= 0 and nexti < n and nextj >= 0 and nextj < n:
if path[nexti][nextj] == 'Q':
return False
return True
# 判断第i层可以放置的所有位置(当前行的所有位置),i从0开始
def back_track(path, i):
# 结束条件
if i == n:
res.append(copy.deepcopy(path)) # 注意使用深拷贝
return
for j in range(n): # 遍历当前层的所有选择
if can(i, j) == False: # 判断第i层的j位置是否合法,进行剪枝操作
continue
path[i][j] = 'Q' # 做选择
back_track(path, i+1) # 回溯
path[i][j] = '.' # 撤销选择
back_track(path, 0)
str_res = [[''.join(line) for line in m] for m in res] # 转换格式
return str_res
# s = Solution()
# print(s.solveNQueens(4))
# 小实验用于测试
# path = [['.', '.' , '.'], ['.', '.' , '.']]
# a = path[:][:]
# path[1][0] = 'O'
# print(a)
# a = '....'
# a[1] = 'o'
# print(a)
- 回溯实际上是遍历决策树,通过遍历每一种情况,从而确定哪些路径符合要求,其中时间复杂度为O(n!),比如在不含重复元素的“全排列”中,共有n!种解。这也是回溯算法的⼀个特点,不像动态规划存在重叠⼦问题可以优化,回溯算法就是纯暴⼒穷举,复杂度⼀般都很⾼。
- 基本代码流程
result = []
def backtrack(路径, 选择列表):
if 满⾜结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择 # 对应树的前序遍历
backtrack(路径, 选择列表)
撤销选择 # 对应树的后续遍历
ps:前序遍历的代码在进⼊某⼀个树的节点之前的那个时间点执⾏,后序遍历代码在离开某个节点之后的那个时间点执⾏。我们要在递归之前做出选择,在递归之后撤销刚才的选择。