题目:
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
示例:
输入: 4 输出: [ [".Q..", // 解法 1 "...Q", "Q...", "..Q."], ["..Q.", // 解法 2 "Q...", "...Q", ".Q.."] ] 解释: 4 皇后问题存在两个不同的解法。
思路:
1)需要哪些函数?需要一个函数来判断我们放置当前行的皇后的位置是否冲突,需要一个函数帮助我们递归去放置皇后。
2)用state元组模拟棋盘和皇后的放置情况。我们选一个pos,(从0-num中),判断当前这个pos与之前的放置冲不冲突,不冲突就继续用同样的方法放,冲突的话(所有for选的pos都冲突)就等待for遍历完会自动回到上一层for,会改变上一层的皇后的位置。如果最后一层了我们选的pos还不冲突,证明我们完成了一次解,于是添加到结果中。
3)代码难理解的地方:
a)我们用state构造棋盘,代表皇后的位置,它的长度是逐渐增加的
b)冲突函数我们是对下一次要放进来的皇后的位置作判断,它需要遍历之前所有的皇后位置,看是否处于同一列或对角线上。
c)在for循环中使用递归。于是,我们for的对象就是一个可迭代的很大的生成器,它包含着我们在这个位置取(pos,)后能成功构造棋盘的所有结果。
d)使用yield。yield不同于return, yield后会从上一个yield的位置继续开始,而不是像return一样结束这个函数。
class Solution:
def solveNQueens(self, n):
"""
:type n: int
:rtype: List[List[str]]
"""
res = []
final_ans = []
ans_list = [-1 for _ in range(n)]
final_ans = list(self.queens(n, final_ans, ()))
#final_ans里储存的是N皇后成功放置后的一个数字组成的元组,各个数字代表各行皇后所在的列数
for each_ans in final_ans:
final = []
for index in each_ans:
#构建最终答案,成为题目需要的形式
row = '.'*index +'Q'*1 + '.'*(n-index-1)
final += [row]
res.append(final)
return res
def queens(self, num, final_ans, state = ()):
for pos in range(num):
#pos指的是当前皇后应该放置的横坐标,也就是所在的列。
if not self.conflict(state, pos):
#产生当前皇后的位置信息
#如果只剩一个皇后没有放置
if len(state) == num-1:
yield (pos,)
#否则,把当前皇后的位置信息,添加到状态列表里,并传递给下一皇后。
#程序要从前面的皇后得到包含位置信息的元组(元组不可更改)
#并要为后面的皇后提供当前皇后的每一种合法的位置信息
#所以把当前皇后的位置信息,添加到状态列表里,并传递给下一皇后。
else:
for result in self.queens(num, final_ans, state+(pos,)):
yield (pos, ) + result
def conflict(self, state, nextX):
#nextY表示当前棋盘构造的长度,也就是下一个皇后应该落在的行的编号
nextY = len(state)
for i in range(nextY):
#遍历之前的行,state[i]表示他们所在的列数,i表示他们所在的行数
if abs(state[i]-nextX) in (0, nextY-i):
return True
return False