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

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

相关推荐
轮到我狗叫了3 小时前
栈的应用,力扣394.字符串解码力扣946.验证栈序列力扣429.N叉树的层序遍历力扣103.二叉树的锯齿形层序遍历
java·算法·leetcode
小爬虫程序猿3 小时前
Python爬虫:深度解析商品详情的自动化之旅
爬虫·python·自动化
pursuit_csdn3 小时前
力扣 238. 除自身以外数组的乘积
数据结构·算法·leetcode
数学人学c语言3 小时前
从熟练Python到入门学习C++(record 6)
c++·python·学习
skaiuijing5 小时前
Sparrow系列拓展篇:消息队列和互斥锁等IPC机制的设计
c语言·开发语言·算法·操作系统·arm
C++忠实粉丝6 小时前
计算机网络socket编程(5)_TCP网络编程实现echo_server
网络·c++·网络协议·tcp/ip·计算机网络·算法
kim56597 小时前
excel版数独游戏(已完成)
算法·游戏·excel·数独
cv君7 小时前
【AI最前线】DP双像素sensor相关的AI算法全集:深度估计、图像去模糊去雨去雾恢复、图像重建、自动对焦
算法
Ocean☾8 小时前
C语言-详细讲解-P1217 [USACO1.5] 回文质数 Prime Palindromes
c语言·数据结构·算法
沐泽Mu8 小时前
嵌入式学习-C嘎嘎-Day08
开发语言·c++·算法