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

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

相关推荐
小白学大数据10 分钟前
Python爬虫开发中的分析与方案制定
开发语言·c++·爬虫·python
Shy9604181 小时前
Doc2Vec句子向量
python·语言模型
ChoSeitaku3 小时前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
DdddJMs__1353 小时前
C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
c语言·leetcode·题解
Fuxiao___4 小时前
不使用递归的决策树生成算法
算法
我爱工作&工作love我4 小时前
1435:【例题3】曲线 一本通 代替三分
c++·算法
秀儿还能再秀4 小时前
机器学习——简单线性回归、逻辑回归
笔记·python·学习·机器学习
白-胖-子4 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
workflower4 小时前
数据结构练习题和答案
数据结构·算法·链表·线性回归
好睡凯4 小时前
c++写一个死锁并且自己解锁
开发语言·c++·算法