Leetcode 51&52 - N皇后问题

题目:N queens
将n个皇后放在n*n的棋盘上,任何两个皇后都不能攻击到对方

思路分析一:递归

N行N列的表格,每行有N列个单元格可以摆放"皇后",每将“皇后”摆放在一列,就看下一行是否可以继续摆放,直到不满足条件回溯,或者最终摆放成功,产生一个成功摆放方案。

可行性剪枝

用三个数组分别记录之前已成功摆好的"皇后"们的列位置、行列之和、行列之差。
如果当前摆放"皇后"所在列已有,或行列之和已有,或行列之差已有,则代表与之前的皇后在同一行、或同一斜线上,即不满足条件停止递归

递归截止条件

当将所有行都摆放完皇后后,即代表一次成功的摆放

代码

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        def DFS(queens, xy_subb, xy_sum):
            y_row = len(queens)
            if y_row == n:
                result.append(queens)
                return None
            for x_col in range(n):
                su, sm = y_row - x_col, y_row + x_col 
                if x_col not in queens and su not in xy_subb and sm not in xy_sum:
                    DFS(queens+[x_col], xy_subb+[su], xy_sum+[sm])
        
        result = []
        DFS([], [], [])
        return [['.'*i + 'Q' + '.'*(n-i-1) for i in queens] for queens in result]

时间复杂度为指数级别,空间复杂度也为指数级

思路分析二:递归+生成器

逐行摆放皇后,如果最终能在最后一行摆放成功,则代表这是一个成功的摆放方案,则生成器生成当前的“皇后”的摆放情况,并逐层回溯组合程完整的摆放方案,

可行性剪枝

将当前要摆放的“皇后”行、列位置与之前已经摆好的皇后位置做比较,如果列差为0(代表同一列)或者列差和行差绝对值相等(代表在同一斜线上),即方案不可行,停止递归

递归截止条件

能成功将最后一个皇后摆放到最后一行

代码

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        def DFS(queens=()):
            def conflict(): 
                y_row = len(queens)
                for row in range(y_row):
                    if abs(queens[row] - x_col) in (0, y_row - row):
                        return True
                return False
            
            for x_col in range(n):
                if not conflict():
                    if len(queens) == n - 1:
                        yield (x_col,)
                    else:
                        for result in DFS(queens+(x_col,)):
                            yield (x_col,) + result
        return [['.'*i + 'Q' + '.'*(n-i-1) for i in queens] for queens in DFS()]

该方案比思路一运行要慢,因为是通过计算来判断是否满足摆放条件的;但空间复杂度方面则有优势,每个位置都少用两个列表,而且使用了生成器而不是列表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值