n 皇后问题
n 皇后问题研究的是如何将 n 个皇后放置在 n × n 的棋盘上,并且使皇后彼此之间不能相互攻击。(即:任意两个皇后之间不能在同一行、同一列或同一斜线)
给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。
两种解法时间复杂度都是O(n!),位运算在常数时间做了极大优化
简单解法
思路比较简单 无注释
// java 递归 + 深搜
// 执行用时:13 ms, 在所有 Java 提交中击败了5.14%的用户
// 内存消耗:34.9 MB, 在所有 Java 提交中击败了96%的用户
class Solution {
public int totalNQueens(int n) {
int[] queen = new int[n];
return solve(queen, 0, n);
}
public int solve(int[] queen, int i, int n){
if(i == n) return 1;
int res = 0;
for(int j = 0; j < n; j++){
queen[i] = j;
if(isValid(queen, i + 1)){
res += solve(queen, i + 1, n);
}
}
return res;
}
public boolean isValid(int[] queen, int i){
for(int m = 1; m < i; m++){
for(int n = 0; n < m; n++){
int x1 = m, y1 = queen[m];
int x2 = n, y2 = queen[n];
if(y1 == y2 || Math.abs((y2-y1) * 1.0 /(x2-x1) * 1.0) == 1.0)
return false;
}
}
return true;
}
}
位运算解法
// java 递归 + 位运算 + 深搜
// 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
// 内存消耗:35.1 MB, 在所有 Java 提交中击败了79.63%的用户
class Solution {
public int totalNQueens(int n) {
//只能处理32位以内
if(n <= 0 || n > 32) return 0;
//limit: 后n位为1, 前32-n位为0的数字,所有皇后的位置限制在limit二进制位为1的位置里
int limit = n == 32 ? -1 : (1 << n) - 1;
return solve(limit, 0, 0, 0); //limit始终不变, n个位为1。后三个参数为0,无皇后所以无限制
}
// limit: 皇后位的限制 所有皇后的位置限制在limit二进制位为1的位置里
// columnLimit:同列限制
// leftLimit:左下方斜线限制
// rightLimit:右下方斜线限制
public int solve(int limit, int columnLimit, int leftLimit, int rightLimit){
//所有列都被占用
if (limit == columnLimit) {
return 1;
}
// 所有不能放皇后的位置:
int forbid = columnLimit | leftLimit | rightLimit;
// 所有可放皇后的位置 一行解决:(pos的二进制为1的数位可放皇后)
int pos = limit & (~forbid); //与limit做&运算是为了去掉前置0
int res = 0;
// 提取出pos的每一个皇后 若pos == 0则无皇后位
while (pos != 0) {
// 每次取出最低位的皇后
int queue = pos & ( ~pos + 1 );
pos -= queue;
res += solve(limit,
columnLimit | queue,
(leftLimit | queue) << 1,
(rightLimit | queue) >> 1); //右斜线限制为 >>>
}
return res;
}
}