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 题目总结

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

相关推荐
belong_to_you17 分钟前
python模块——tqdm
python
fen_fen19 分钟前
学习笔记(26):线性代数-张量的降维求和,简单示例
笔记·学习·算法
王禄DUT20 分钟前
炉石传说 第八次CCF-CSP计算机软件能力认证
c++·算法
白熊1881 小时前
【推荐算法】DeepFM:特征交叉建模的革命性架构
算法·架构·推荐算法
L_cl1 小时前
【Python 算法零基础 4.排序 ⑪ 十大排序算法总结】
python·算法·排序算法
Vertira1 小时前
Pytorch安装后 如何快速查看经典的网络模型.py文件(例如Alexnet,VGG)(已解决)
人工智能·pytorch·python
小刘不想改BUG1 小时前
LeetCode 70 爬楼梯(Java)
java·算法·leetcode
老歌老听老掉牙1 小时前
使用 SymPy 进行向量和矩阵的高级操作
python·线性代数·算法·矩阵·sympy
DX_dove1 小时前
pytorch3d+pytorch1.10+MinkowskiEngine安装
人工智能·pytorch·python
lifallen1 小时前
Flink checkpoint
java·大数据·算法·flink