本文目录
- [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 题目总结
题目难度:困难
数据结构:数组
应用算法:回溯法