- 思路:注释
- 方法一:利用位运算,当前行更上一行或运算可得到当前行的某一列不可取,当前行跟上一行左移动一位或运算可以得到左斜线位置不可取,当前行跟上一行右移一位或运算可以得到右斜线位置不可取,剩下就是可以进行尝试的位置.
- 方法二:主要判断当前行列是否可取,如果不可取那么,那么res返回0, 逆推测上去,此路不通.
class Solution {
// 第一种解法
public int totalNQueens(int n) {
if(n < 1 || n > 32) {
return 0;
}
int limit = n == 32 ? -1 : (1 << n) - 1;
return process2(limit, 0,0,0);
}
// limit 划定了问题的规模 =》 固定范围
// colLim 列的限制, 1的位置不能放皇后, 0的位置可以放
// leftDiaLim 左斜线的限制, 1的位置不能放皇后, 0的位置可以
// rightDiaLim 右斜线的限制, 1的位置不能放皇后, 0的位置可以
public static int process2(
int limit,
int colLim,
int leftDiaLim,
int rightDiaLim
) {
if(colLim == limit) {
return 1;
}
// 所有可以放皇后的位置都在pos上
// colLim | leftDiaLim | rightDiaLim => 总限制
// ~(colLim | leftDiaLim | rightDiaLim) 左侧的一堆0干扰,右侧每个1
int pos = limit & (~(colLim | leftDiaLim | rightDiaLim));// 可以放皇后的位置
int mostRightOne = 0;
int res = 0;
while(pos != 0) {
mostRightOne = pos & (~pos + 1);
pos = pos - mostRightOne;
res += process2(limit, colLim | mostRightOne,
(leftDiaLim | mostRightOne) << 1,
(rightDiaLim | mostRightOne) >> 1
);
}
return res;
}
// 第二种解法
// public int totalNQueens(int n) {
// if(n < 1) {
// return 0;
// }
// int[] record = new int[n];
// return process1(0, record,n);
// }
// public static int process1(int i, int[] record,int n) {
// if(i == n) {
// return 1;
// }
// int res = 0;
// for(int j = 0; j < n; j++) {
// if(isValid(record,i,j)){
// record[i] = j;
// res += process1(i + 1, record, n);
// }
// }
// return res;
// }
// public static boolean isValid(int[] record, int i, int j) {
// for(int k = 0; k < i; k++) {
// if(j == record[k] || Math.abs(record[k] - j) == Math.abs(k - i)) {
// return false;
// }
// }
// return true;
// }
}