LeetCode【0051】N皇后

本文目录

  • [1 中文题目](#1 中文题目)
  • [2 求解方法:回溯法](#2 求解方法:回溯法)
    • [2.1 方法思路](#2.1 方法思路)
    • [2.2 Python代码](#2.2 Python代码)
    • [2.3 复杂度分析](#2.3 复杂度分析)
  • [3 题目总结](#3 题目总结)

1 中文题目

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

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

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

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

示例:

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

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

提示:

  • 1 ≤ n ≤ 9 1\leq n \leq 9 1≤n≤9

2 求解方法:回溯法

2.1 方法思路

方法核心

使用回溯法逐行放置皇后,通过三个集合分别记录已被占用的列、主对角线和副对角线,利用主对角线上r-c值相等和副对角线上r+c值相等的特性来快速判断位置是否可用,避免了逐个检查的开销,同时使用回溯来探索所有可能的解。

实现步骤

(1)初始化阶段:

  • 创建结果列表存储所有解法
  • 创建queens列表存储已放置的皇后位置
  • 创建三个集合分别记录被占用的列和对角线

(2)回溯过程:

  • 从第一行开始,逐行放置皇后
  • 对每一行,尝试在每一列放置皇后
  • 检查当前位置是否满足条件
  • 放置皇后并更新三个集合的信息
  • 递归处理下一行
  • 回溯时移除当前皇后并清理相关信息

(3)位置检查:

  • 检查当前列是否已被占用
  • 检查主对角线(r-c)是否已被占用
  • 检查副对角线(r+c)是否已被占用
  • 所有条件都满足才能放置皇后

(4)生成结果:

  • 当放置了n个皇后时生成棋盘表示
  • 将当前解加入结果列表
  • 继续回溯寻找其他解

方法示例

以 n = 4 的情况为例:

python 复制代码
初始状态:
queens = []
cols = set()
diag1 = set()
diag2 = set()

第一次尝试(从第一行开始):
row = 0, col = 0
放置第一个皇后:
queens = [(0,0)]
cols = {0}
diag1 = {0}
diag2 = {0}
棋盘状态:
Q...
....
....
....

继续到第二行(row=1):
尝试col=2(col=0,1不行因为被攻击)
queens = [(0,0), (1,2)]
cols = {0,2}
diag1 = {0,-1}
diag2 = {0,3}
棋盘状态:
Q...
..Q.
....
....

继续到第三行(row=2):
发现无法放置,回溯到第二行...

经过多次回溯,找到第一个完整解:
最终queens = [(0,1), (1,3), (2,0), (3,2)]
对应棋盘:
.Q..
...Q
Q...
..Q.

继续回溯找其他解...

2.2 Python代码

python 复制代码
class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        # 存储所有解法
        results = []
        # 用于存储已放置的皇后的位置信息
        queens = []
        # 记录列、主对角线、副对角线是否被占用
        cols = set()
        diag1 = set()  # 主对角线 r-c 为常数
        diag2 = set()  # 副对角线 r+c 为常数

        def create_board():
            # 根据皇后位置创建棋盘
            board = []
            for r, c in queens:
                row = '.' * c + 'Q' + '.' * (n-c-1)
                board.append(row)
            return board

        def backtrack(row):
            # 如果已经放置了n个皇后,说明找到一个解
            if row == n:
                results.append(create_board())
                return

            # 尝试在当前行的每一列放置皇后
            for col in range(n):
                # 检查当前位置是否可以放置皇后
                if col not in cols and \
                   row - col not in diag1 and \
                   row + col not in diag2:
                    # 放置皇后,并记录相关信息
                    queens.append((row, col))
                    cols.add(col)
                    diag1.add(row - col)
                    diag2.add(row + col)
                    
                    # 继续处理下一行
                    backtrack(row + 1)
                    
                    # 回溯:移除当前放置的皇后
                    queens.pop()
                    cols.remove(col)
                    diag1.remove(row - col)
                    diag2.remove(row + col)

        backtrack(0)
        return results

2.3 复杂度分析

  • 时间复杂度:O(N!)
    • 第一行有N种选择
    • 第二行最多有N-1种选择
    • 第三行最多有N-2种选择
    • 依此类推
    • 实际运行时间会小于N!,因为许多分支会被提前剪枝
  • 空间复杂度:O(N)
    • queens列表存储N个皇后位置:O(N)
    • 三个集合最多存储N个元素:O(N)
    • 递归调用栈深度为N:O(N)
    • 存储每个解需要O(N)空间

3 题目总结

题目难度:困难
数据结构:数组
应用算法:回溯法

相关推荐
凭君语未可4 分钟前
豆包MarsCode:小C点菜问题
算法
深蓝海拓17 分钟前
Pyside6(PyQT5)中的QTableView与QSqlQueryModel、QSqlTableModel的联合使用
数据库·python·qt·pyqt
C语言魔术师24 分钟前
【小游戏篇】三子棋游戏
前端·算法·游戏
自由自在的小Bird24 分钟前
简单排序算法
数据结构·算法·排序算法
无须logic ᭄25 分钟前
CrypTen项目实践
python·机器学习·密码学·同态加密
Channing Lewis38 分钟前
flask常见问答题
后端·python·flask
Channing Lewis39 分钟前
如何保护 Flask API 的安全性?
后端·python·flask
水兵没月2 小时前
钉钉群机器人设置——python版本
python·机器人·钉钉
我想学LINUX3 小时前
【2024年华为OD机试】 (A卷,100分)- 微服务的集成测试(JavaScript&Java & Python&C/C++)
java·c语言·javascript·python·华为od·微服务·集成测试
数据小爬虫@6 小时前
深入解析:使用 Python 爬虫获取苏宁商品详情
开发语言·爬虫·python