N 皇后问题就是深搜和回溯的最好练手
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
#第一种写法:
class Solution:
def addchar(self,index_x,n):
s = ''
for i in range(n):
if i == index_x:
s = s + 'Q'
else:
s = s + '.'
return s
def go(self,level,n,res:list):
if level == n:
self.ans.append(res)
return
if level != 0:
for i in range(n):
flag = True
for x,y in self.index:
if (abs(level - y) == abs(i - x)) or x == i:
flag = False
break
if flag:
self.index.append((i,level))
self.go(level+1,n,res+[self.addchar(i,n)]) #这样传递res参数就相当于对res参数进行了一次深拷贝,传递的时候是把res+[self.addchar(i,n)]的运算结果直接赋值给下一层的res,
#而对于赋值操作赋值号=两边的变量指向同一个内存空间,改变一个变量时另外一个也将改变,但这里的两个变量不会被改变,因为每次运算的结果res+[self.addchar(i,n)]都是不同的,
#也就是说要放在不同的内存空间中,而在后面的运算中又不会改变这些变量。而且这样不需要在后面对res函数弹出操作,因为当回溯的时候,回溯到上一层就自动去除了递归进入时加的[self.addchar(i,n)].
self.index.pop(-1)
else:
continue
else:
for i in range(n):
self.index.append((i,level))
self.go(level+1,n,res+[self.addchar(i,n)])
self.index.pop(-1)
def solveNQueens(self, n: int) -> List[List[str]]:
if n == 0:
return []
self.ans = []
self.index = []
self.go(0,n,[])
return self.ans
a
#第二种写法:
import copy
class Solution:
def addchar(self, index_x, n):
s = ''
for i in range(n):
if i == index_x:
s = s + 'Q'
else:
s = s + '.'
return s
def go(self, level, n, res):
if level == n:
a = copy.deepcopy(res) # 深拷贝,深拷贝之后,两个变量就是没有关系的独立变量,只是值相同而已。
self.ans.append(a)
return
if level != 0:
for i in range(n):
flag = True
for x, y in self.index:
if (abs(level - y) == abs(i - x)) or x == i:
flag = False
break
if flag:
res.append(self.addchar(i, n))
self.index.append((i, level))
self.go(level + 1, n, res)
self.index.pop(-1)
res.pop(-1)
else:
continue
else:
for i in range(n):
res.append(self.addchar(i, n))
self.index.append((i, level))
self.go(level + 1, n, res) # 这里的res,是先append(前两行)再传值的,这样就要每次回溯之后,手动的将上次的那一行的排列弹出,该列位于res的最后。
self.index.pop(-1)
res.pop(-1) # 回溯,弹出上次append的元素
def solveNQueens(self,n):
if n == 0:
return []
self.ans = []
self.index = []
self.go(0, n, [])
return self.ans
# 开始的时候,写的代码是这样的,整整难了我一个上午加晚上。
def go(self,level,n,res:list):
if level == n: # 这里的res是和上层的共用一个内存空间,当上层的pop(-1)时,ans也会变
self.ans.append(res)
return
if level != 0:
for i in range(n):
flag = True
for x,y in self.index:
if (abs(level - y) == abs(i - x)) or x == i:
flag = False
break
if flag:
res.append([self.addchar(i,n)]) #先将找到的一行的排列append入res列表中
self.index.append((i,level))
self.go(level+1,n,res+[self.addchar(i,n)])
res.pop(-1) # 进行回溯,要弹出之前行排列
self.index.pop(-1)
else:
continue
else:
for i in range(n):
# res.append(self.addchar(i,n))
self.index.append((i,level))
self.go(level+1,n,res+[self.addchar(i,n)])
self.index.pop(-1)
#这种写法的问题出在深浅拷贝上,这个res直接赋值给了下层的res,当下层的res改变时,上层的res也会改变