LeetCode 第52题:N皇后 II
题目描述
n 皇后问题 研究的是如何将 n 个皇后放置在 n × n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。
难度
困难
题目链接
示例
示例 1:
输入:n = 4
输出:2
解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:
输入:n = 1 输出:1
提示
1 <= n <= 9- 皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一行、同一列或同一斜线上。
解题思路
位运算优化的回溯算法
这道题是N皇后问题的简化版,只需要返回解的数量。我们可以使用位运算来优化判断过程,提高效率。
关键点:
- 使用位运算记录列、对角线的占用情况
- 通过位操作快速判断位置是否可用
- 不需要生成具体的棋盘表示
- 利用补集运算获取可用位置
具体步骤:
- 使用三个整数记录列和两个方向对角线的占用情况
- 通过位运算计算当前行可用的位置
- 选择一个可用位置放置皇后
- 更新占用状态并递归到下一行
- 回溯时恢复状态
图解思路
算法步骤分析表
| 步骤 | 当前行 | 列占用 | 对角线1 | 对角线2 | 说明 |
|---|---|---|---|---|---|
| 初始 | 0 | 0 | 0 | 0 | 开始状态 |
| 第1步 | 0 | 2 | 2 | 2 | 放置第1个 |
| 第2步 | 1 | 10 | 20 | 5 | 放置第2个 |
| 第3步 | 2 | 11 | 22 | 7 | 放置第3个 |
状态/情况分析表
| 情况 | 输入 | 输出 | 说明 |
|---|---|---|---|
| n=1 | 1 | 1 | 最简单情况 |
| n=4 | 4 | 2 | 标准情况 |
| n=8 | 8 | 92 | 复杂情况 |
代码实现
C# 实现
public class Solution {
private int count = 0;
public int TotalNQueens(int n) {
DFS(n, 0, 0, 0, 0);
return count;
}
private void DFS(int n, int row, int columns, int diag1, int diag2) {
if (row == n) {
count++;
return;
}
// 获取当前行可用的位置
int availablePositions = ((1 << n) - 1) & (~(columns | diag1 | diag2));
while (availablePositions != 0) {
// 获取最低位的1
int position = availablePositions & (-availablePositions);
// 清除最低位的1
availablePositions = availablePositions & (availablePositions - 1);
DFS(n, row + 1,
columns | position,
(diag1 | position) << 1,
(diag2 | position) >> 1);
}
}
}
执行结果
- 执行用时:36 ms
- 内存消耗:25.3 MB
代码亮点
- 🎯 使用位运算优化判断过程
- 💡 通过补集运算快速获取可用位置
- 🔍 利用位操作特性优化性能
- 🎨 代码简洁高效
常见错误分析
- 🚫 位运算操作顺序错误
- 🚫 对角线移位方向搞错
- 🚫 没有正确处理位掩码
- 🚫 递归终止条件错误
解法对比
| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
|---|---|---|---|---|
| 普通回溯 | O(n!) | O(n) | 容易理解 | 性能一般 |
| 集合回溯 | O(n!) | O(n) | 实现简单 | 内存消耗大 |
| 位运算优化 | O(n!) | O(n) | 性能最佳 | 不易理解 |