leetcode 51.N皇后问题详细题解(回溯法)

原题地址
官方解答
第二个叫做 回溯法.

我们来想象一下,当在棋盘上放置了几个皇后且不会相互攻击。但是选择的方案不是最优的,因为无法放置下一个皇后。此时我们该怎么做?回溯。意思是回退一步,来改变最后放置皇后的位置并且接着往下放置。如果还是不行,再 回溯。
在这里插入图片描述
方法1:回溯
在建立算法之前,我们来考虑两个有用的细节。

一行只可能有一个皇后且一列也只可能有一个皇后。

这意味着没有必要再棋盘上考虑所有的方格。只需要按列循环即可。

对于所有的主对角线有 行号 + 列号 = 常数,对于所有的次对角线有 行号 - 列号 = 常数.

这可以让我们标记已经在攻击范围下的对角线并且检查一个方格 (行号, 列号) 是否处在攻击位置。
在这里插入图片描述
现在已经可以写回溯函数 backtrack(row = 0).
从第一个 row = 0 开始.
循环列并且试图在每个 column 中放置皇后.
如果方格 (row, column) 不在攻击范围内
在 (row, column) 方格上放置皇后。
排除对应行,列和两个对角线的位置。
If 所有的行被考虑过,row == N
意味着我们找到了一个解
Else
继续考虑接下来的皇后放置 backtrack(row + 1).
回溯:将在 (row, column) 方格的皇后移除.

去题解里看一下官方给的幻灯片!!!

修改了原题解中的主次对角线代码错误问题(row+col和row-col)

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        #用于存放皇后位置(row,col)
        queens = set()
        #用于保存输出
        output = []
        #用于存放queen所在列的情况
        cols = [0]*n
        #主对角线  和为定值  通过这个定值确定一主对角线位置
        hill_diagonals = [0]*(2*n-1)
        #次对角线  差为定值 通过这个定值确定一次对角线位置
        dale_diagonals = [0]*(2*n-1)
        def place_queen(row,col):
            #加入皇后的位置而且把相应列,主次对角线置为不能再皇后
            queens.add((row,col))
            cols[col] = 1
            hill_diagonals[row+col]=1
            dale_diagonals[row-col]=1
        def remove_queen(row,col):
            #删除皇后的位置而且把相应列,主次对角线置为可以放皇后
            queens.remove((row,col))
            cols[col] = 0
            hill_diagonals[row+col]=0
            dale_diagonals[row-col]=0
        def could_place(row,col):
            #如果这个位置(row,col),列上有皇后或所在主次对角线有皇后,返回False,反之True
            return not (cols[col]+hill_diagonals[row+col]+dale_diagonals[row-col])
        def add_solution():
            #用于格式化保存答案
            #每一个solution是一种解
            solution = []
            for _,col in sorted(queens):
                solution.append('.'*col+'Q'+'.'*(n-col-1))
            output.append(solution)
        def backtrack(row = 0):#从第一行开始
            #遍历所有列
            for col in range(n):
                #如果这个行列可以放皇后
                if could_place(row,col):
                    #就放皇后
                    place_queen(row,col)
                    #如果到了最后一行
                    if row+1 == n:
                        #则这个排列成立,保存一个解
                        add_solution()
                    #如果不是最后一行
                    else :
                        #进入下一行并判断
                        backtrack(row+1)
                    #这个位置皇后状态判断完则把她存在的痕迹抹去
                    remove_queen(row,col)
        backtrack()
        return output
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值