N皇后问题(含位运算版本)
1.经典方法解决N皇后问题
题目
测试连接:leetcode.cn/problems/n-...
题目中:1<=n<=9,n的范围较小,我们可以枚举所有可能
代码:
java
class Solution {
private List<List<String>> ans = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
int[] path = new int[n];
f(path,0,n);
return ans;
}
//策略:每一行开始枚举,看每一行的棋子应该放置哪个位置
//path数组:记录每一行的棋子放置的列数
//cur:当前的行
public void f(int[] path ,int cur,int n){
//递归终止条件
if(cur == n){
List<String> list = new ArrayList();
for(int i=0;i<n;i++){
StringBuilder sb = new StringBuilder();
for(int j=0;j<n;j++){
if(path[i]==j) sb.append('Q');
else sb.append('.');
}
list.add(sb.toString());
}
ans.add(list);
return;
}
//枚举每一列,看看能不能放
for(int col=0;col<n;col++){
//check函数检查
if(check(path,cur,col)){
path[cur]=col;
f(path,cur+1,n);
}
}
}
public boolean check(int[] path,int row,int col){
for(int i=0;i<row;i++){
//这里利用斜率==1的知识,巧妙处理了两条对角线
if(path[i]==col || Math.abs(row-i)==Math.abs(col-path[i])) return false;
}
return true;
}
}
时间复杂度: O(n!)
2.用位运算解决N皇后问题
题目
测试链接:leetcode.cn/problems/n-...
代码
java
class Solution {
//用位运算实现递归版本
public int totalNQueens(int n) {
//比如5皇后问题,limit= ...00011111,最右边有5个1
int limit = (1<<n) -1;
return f2(limit,0,0,0);
}
//col:列的限制条件,记录哪些列放置了皇后,0代表当前行可以放置,1代表不可以放置
//left:右上角到左下角的限制条件,0代表当前行可以放置,1代表不可以放置
//right:左上角到右下角的限制条件,0代表当前行可以放置,1代表不可以放置
public int f2(int limit,int col,int left,int right){
//递归终止条件
if(col == limit){
return 1;
}
//可以放置的位置
int cadidate = col | left | right;
//取反是将1变为可放置的,0变为不可放置,方便我们后面运算
//&limit:是去掉无用的信息
cadidate = ((~cadidate) & limit);
int ans = 0;
while(cadidate != 0){
//取出最右侧的1
int choice = cadidate & (~cadidate+1);
//更新candidate
cadidate ^= choice;
//更新下一行的条件
ans += f2(limit,col | choice,(left | choice)<<1 ,(right | choice) >>1);
}
return ans;
}
}
时间复杂度:O(n!)
位运算的速度比用path数组记录更快
3.声明
以上的代码是听了左神(b站左程云)的教学后自己写的