51. N-Queens
题目:
The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.
Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q'
and '.'
both indicate a queen and an empty space respectively.
For example,
There exist two distinct solutions to the 4-queens puzzle:
[ [".Q..", // Solution 1 "...Q", "Q...", "..Q."], ["..Q.", // Solution 2 "Q...", "...Q", ".Q.."] ]
代码:
N皇后问题,经典问题,想想应该用递归来做,逻辑想想也不复杂,但就是实现起来总觉得好困难!
最近在学习python的生成器yield,用生成器可以很优雅的实现这个问题:
生成器并不会一次返回所有结果,而是每次遇到
yield
关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用。yield类似于普通函数执行中的return,不同的是会记录当前函数运行状态和结果,下次接着该状态执行。代码参考Magnus Lie Hetland的《python基础教程》第二版:
#encoding:utf-8
import random
class Solution(object):
#判断新增位置是否与之前位置冲突
#state用元组(tupe)保存之前换后的位置,例如0-3行皇后的位置保存为(1,3,0)
#nextX代表下一个皇后的水平位置,和state的所有元素比较
#保证不在一条线上(X坐标相同)且不在一个对角线上(Y坐标位置的差不等于X坐标位置的差),代码中:X坐标位置的差 not in(0, nextY-i)
def conflict(self, state, nextX):
nextY = len(state)
for i in range(nextY):
if abs(state[i]-nextX) in (0, nextY-i):
return True
return False
#输入棋盘大小num和当前皇后位置状态state
#用conflict判断下一行皇后的位置pos是否与state中的皇后位置冲突
#冲突就放弃这个迭代分支
#不冲突继续:分两种情况分支:
# 1.下一行皇后是最后一行的皇后,不冲突的话就保存结果,无需迭代
# 2.下一行皇后不是最后一行皇后,不冲突的话迭代调用该函数(queens()),迭代变量唯一区别是state的中增加当前皇后的位置,从而用来判断下一行皇后
#注意生成器的使用:
#生成器并不会一次返回所有结果,而是每次遇到yield关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用。
def queens(self, num=8,state=()):
for pos in range(num):
if not self.conflict(state, pos):
if len(state) == num-1:
print ('state: ',state)
#print ('last pos: ',pos)
yield(pos, )
else:
for result in self.queens(num, state + (pos,)):
#print ('state: ',state)
#print ('pos: ',pos)
#print ('result: ',result)
yield(pos, )+result
#该函数仅仅为了按题目要求格式化输出结果
def prettyprint(self, one_way):
result_list=[]
def line(pos, length = len(one_way)):
return ('.'*(pos) + 'Q' + '.'*(length-pos-1))
for pos in one_way:
result_list.append(line(pos))
return result_list
def solveNQueens(self, n):
"""
:type n: int
:rtype: List[List[str]]
"""
if(n==1): return [["Q"]]
elif(n<=3): return []
res_list = []
solution = list(self.queens(n))
#for i in solution:res_list.append(self.prettyprint(i))
for i in solution:res_list.append(i)
#print (res_list)
#print (self.prettyprint(list(self.queens(n))[0]))
return res_list
if __name__=="__main__":
#print (list(queens(8)))
#prettyprint(random.choice(list(queens(8))))
a = Solution()
print (a.solveNQueens(4))
import random
class Solution(object):
#判断新增位置是否与之前位置冲突
#state用元组(tupe)保存之前换后的位置,例如0-3行皇后的位置保存为(1,3,0)
#nextX代表下一个皇后的水平位置,和state的所有元素比较
#保证不在一条线上(X坐标相同)且不在一个对角线上(Y坐标位置的差不等于X坐标位置的差),代码中:X坐标位置的差 not in(0, nextY-i)
def conflict(self, state, nextX):
nextY = len(state)
for i in range(nextY):
if abs(state[i]-nextX) in (0, nextY-i):
return True
return False
#输入棋盘大小num和当前皇后位置状态state
#用conflict判断下一行皇后的位置pos是否与state中的皇后位置冲突
#冲突就放弃这个迭代分支
#不冲突继续:分两种情况分支:
# 1.下一行皇后是最后一行的皇后,不冲突的话就保存结果,无需迭代
# 2.下一行皇后不是最后一行皇后,不冲突的话迭代调用该函数(queens()),迭代变量唯一区别是state的中增加当前皇后的位置,从而用来判断下一行皇后
#注意生成器的使用:
#生成器并不会一次返回所有结果,而是每次遇到yield关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用。
def queens(self, num=8,state=()):
for pos in range(num):
if not self.conflict(state, pos):
if len(state) == num-1:
print ('state: ',state)
#print ('last pos: ',pos)
yield(pos, )
else:
for result in self.queens(num, state + (pos,)):
#print ('state: ',state)
#print ('pos: ',pos)
#print ('result: ',result)
yield(pos, )+result
#该函数仅仅为了按题目要求格式化输出结果
def prettyprint(self, one_way):
result_list=[]
def line(pos, length = len(one_way)):
return ('.'*(pos) + 'Q' + '.'*(length-pos-1))
for pos in one_way:
result_list.append(line(pos))
return result_list
def solveNQueens(self, n):
"""
:type n: int
:rtype: List[List[str]]
"""
if(n==1): return [["Q"]]
elif(n<=3): return []
res_list = []
solution = list(self.queens(n))
#for i in solution:res_list.append(self.prettyprint(i))
for i in solution:res_list.append(i)
#print (res_list)
#print (self.prettyprint(list(self.queens(n))[0]))
return res_list
if __name__=="__main__":
#print (list(queens(8)))
#prettyprint(random.choice(list(queens(8))))
a = Solution()
print (a.solveNQueens(4))
运行结果:
当然,该算法不是解决八皇后问题的最优解,必定效率不高:
关于更多优秀解法,可以自行google。
第一道解决的LeetCode中Hard难度问题,基本上copy了书中的方法。不过通过逐句的分析学习,还是受益匪浅。