关注
文末的名片达文汐
,回复关键词“力扣源码”,即可获取完整源码!!详见:源码和核心代码的区别
题目详情
n 皇后问题 研究的是如何将 n
个皇后放置在 n × n
的棋盘上,并且使皇后彼此之间不能相互攻击(皇后可以攻击同一行、同一列、同一对角线上的其他皇后)。
给定一个整数 n
,返回 n
皇后问题不同的解决方案的数量。
示例 1:
输入:n = 4
输出:2
解释:4 皇后问题存在两个不同的解法。
示例 2:
输入:n = 1
输出:1
提示:
1 <= n <= 9
解题思路
核心思路: 使用深度优先搜索(DFS)与位运算优化,逐行放置皇后,并通过三个整数记录列、主对角线和副对角线的占用状态,避免冲突。
-
状态表示:
cols
:整数的二进制位表示列的占用情况(第i
位为1
表示第i
列已被占用)。diag1
:整数的二进制位表示主对角线(左上到右下)的占用情况。主对角线索引为row - col + n - 1
(确保非负)。diag2
:整数的二进制位表示副对角线(右上到左下)的占用情况。副对角线索引为row + col
。
-
递归放置皇后:
- 从第
0
行开始,逐行放置皇后。 - 对当前行的每一列进行尝试:
- 检查列、主对角线、副对角线是否冲突(通过位运算快速判断)。
- 若无冲突,更新状态(设置对应位为
1
),递归处理下一行。
- 递归终止:当行数
row == n
时,表示找到一种解法,计数加1
。
- 从第
-
位运算优化:
- 冲突检测:通过
&
运算检查目标位是否为1
。 - 状态更新:通过
|
运算设置新状态,并作为参数传递到下一层递归,避免显式回溯。
- 冲突检测:通过
优点:
- 时间优化:位运算实现快速冲突检测,时间复杂度为 O(n!)。
- 空间优化:仅用三个整数记录状态,空间复杂度为 O(1)。
代码实现(Java)
class Solution {
public int totalNQueens(int n) {
return dfs(0, n, 0, 0, 0);
}
private int dfs(int row, int n, int cols, int diag1, int diag2) {
if (row == n) {
return 1; // 所有行放置完成,找到一种解法
}
int count = 0;
for (int col = 0; col < n; col++) {
// 计算主对角线和副对角线的索引
int d1 = row - col + n - 1; // 主对角线索引(确保非负)
int d2 = row + col; // 副对角线索引
// 检查列、主对角线、副对角线是否冲突
if ((cols & (1 << col)) != 0) continue; // 列冲突
if ((diag1 & (1 << d1)) != 0) continue; // 主对角线冲突
if ((diag2 & (1 << d2)) != 0) continue; // 副对角线冲突
// 递归下一行,更新状态(设置对应位为1)
count += dfs(row + 1, n,
cols | (1 << col),
diag1 | (1 << d1),
diag2 | (1 << d2));
}
return count;
}
}
代码说明
-
递归函数
dfs
参数:row
:当前处理的行。n
:棋盘大小。cols
:列占用状态(二进制位表示)。diag1
:主对角线占用状态。diag2
:副对角线占用状态。
-
关键操作:
- 冲突检测:使用
(state & (1 << index)) != 0
检测目标位是否被占用。 - 状态更新:通过
state | (1 << index)
设置新状态,并传递至下一层递归。 - 递归终止:当
row == n
时,返回1
表示找到一种解法。
- 冲突检测:使用
-
返回值:
- 递归过程中累加所有可行解的数量。