【LeetCode 热题100】 51. N 皇后 缓存的算法思路及python代码

51. N 皇后

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。

示例 1:

在这里插入图片描述

输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

输入:n = 1
输出:[["Q"]]

算法思路

该代码通过 回溯法 解决 N 皇后问题,尝试在棋盘上逐行放置皇后,并通过剪枝条件确保皇后之间不冲突。核心思路如下:

算法步骤

  1. 递归终止条件

    • res 的长度等于 n 时,表示所有皇后已合法放置,将当前棋盘状态保存到结果列表 res_list
  2. 遍历当前行的所有列

    • 对每一列 i,将其加入 res(表示当前行皇后放在第 i 列)。
    • 调用 check 函数检查当前放置是否合法。
    • 若合法,则递归处理下一行。
    • 无论是否合法,回溯时弹出 res 的最后一个元素(撤销当前行的选择)。
  3. 冲突检查(check 函数)

    • 检查新加入的皇后是否与之前行的皇后存在列冲突或斜线冲突。
    • 列冲突:新皇后与任意旧皇后在同一列。
    • 斜线冲突:新皇后与任意旧皇后在同一正斜线(行差 = 列差)或反斜线(行差 = -列差)。
  4. 结果格式转换(built 函数)

    • 将列索引列表转换为题目要求的字符串格式(如 [1,3]".Q..", "..Q.")。

关键点

  • 剪枝策略:仅在当前行皇后放置合法时,才继续递归下一行。
  • 冲突检查逻辑:通过遍历已放置的皇后,检查列和斜线冲突(时间复杂度为 O ( n ) O(n) O(n))。
  • 回溯状态管理:通过 res.append(i)res.pop() 维护路径状态。
  • 结果转换:将列索引转换为棋盘字符串,保证输出符合要求。

复杂度分析

  • 时间复杂度O(n! × n)

    • 最坏情况下(无剪枝),遍历所有可能的排列组合(n!),每次递归需 O ( n ) O(n) O(n) 时间检查冲突。
    • 实际因剪枝优化,复杂度低于 O ( n ! × n ) O(n! × n) O(n!×n),但仍较高。
  • 空间复杂度O(n²)

    • 递归栈深度为 O ( n ) O(n) O(n)
    • 结果列表存储所有解的棋盘字符串,每个解占用 O ( n 2 ) O(n²) O(n2) 空间(n 个字符串,每个长 n)。

算法代码

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        def check(res):
            if not res: return True
            target = res[-1]
            for i in range(len(res)-1):
                if target - (len(res)-(i+1)) == res[i] \
                or target + (len(res)-(i+1)) == res[i] \
                or target == res[i]:
                    return False
            return True
        def backtrack(index=0,res=[]):
            # 时空气泡
            if not check(res):
                return res
            if len(res) == n:
                res_list.append(res[:])
                return res

            # 探索子时空
            for i in range(0,n):
                res.append(i)
                res = backtrack(index+1,res)
                res.pop()
            # 回溯时空气泡
            return res
        def built(res_list):
            result = []
            for res in res_list:
                _str_list = []
                for i in res:
                    _str = ['.'] * n
                    _str[i] = 'Q'
                    _str_list.append("".join(_str))
                result.append(_str_list)
            return result
        res_list = []
        backtrack()
        return built(res_list)

在这里插入图片描述

代码问题与优化

现存问题

  1. 递归参数传递错误

    • backtrack 函数中 res = backtrack(index+1, res) 会覆盖当前路径状态,导致后续 res.pop() 操作错误。
    • 修复:直接通过 appendpop 维护 res,无需重新赋值。
  2. 冲突检查效率低

    • check 函数每次遍历所有已放置皇后,时间复杂度为 O(n)。
    • 优化:使用哈希集合记录被占用的列、正斜线(行-列)、反斜线(行+列),将冲突检查降至 O(1)。
  3. 冗余参数 index

    • index 未被使用,可移除以简化逻辑。
优化后代码示例
class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        def backtrack(row, cols, diag1, diag2, path):
            if row == n:
                res.append(["." * i + "Q" + "." * (n - i - 1) for i in path])
                return
            for col in range(n):
                d1, d2 = row - col, row + col
                if col not in cols and d1 not in diag1 and d2 not in diag2:
                    backtrack(row + 1, cols | {col}, diag1 | {d1}, diag2 | {d2}, path + [col])
        
        res = []
        backtrack(0, set(), set(), set(), [])
        return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值