题目
将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。‘Q’ 和 ‘.’ 分别代表了皇后和空位。
方法一:基于集合的回溯
使用三个集合col、dia1和 dia2分别记录每一列以及两个方向的每条斜线上是否有皇后。Columns表示为0 到N−1的每一列,方向用斜率表示。
具体做法是:使用一个数组记录每行放置的皇后的列下标,依次在每一行放置一个皇后。每次新放置的皇后都不能和已经放置的皇后在同一列以及同一条斜线上,并更新数组中的当前行的皇后列下标。当 N 个皇后都放置完毕,则找到一个可能的解。当找到一个可能的解之后,将数组转换成表示棋盘状态的列表,并将该棋盘状态的列表加入返回列表。
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> solutions=new ArrayList<List<String>>();
int[] queens=new int[n];
Arrays.fill(queens,-1);
Set<Integer> col=new HashSet<Integer>();
Set<Integer> dia1=new HashSet<Integer>();
Set<Integer> dia2=new HashSet<Integer>();
back(solutions,queens,n,0,col,dia1,dia2);
return solutions;
}
public void back(List<List<String>> solutions,int[] queens,int n,int row,Set<Integer> col,Set<Integer> dia1,Set<Integer> dia2){
if(row==n){
List<String> board=generate(queens,n);
solutions.add(board);
}else{
for(int i=0;i<n;i++){
if(col.contains(i)){
continue;
}
int dia=row-i;
if(dia1.contains(dia)){
continue;
}
int dig=row+i;
if(dia2.contains(dig)){
continue;
}
queens[row]=i;
col.add(i);
dia1.add(dia);
dia2.add(dig);
back(solutions,queens,n,row+1,col,dia1,dia2);
queens[row]=-1;
col.remove(i);
dia1.remove(dia);
dia2.remove(dig);
}
}
}
public List<String> generate(int[] queens,int n){
List<String> board=new ArrayList<String>();
for(int i=0;i<n;i++){
char[] row=new char[n];
Arrays.fill(row,'.');
row[queens[i]]='Q';
board.add(new String(row));
}
return board;
}
}
复杂度分析
时间复杂度:O(N!),其中 N 是皇后数量。
空间复杂度:O(N)。
方法二:基于位运算的回溯
利用位运算记录皇后的信息,就可以将记录皇后信息的空间复杂度从 O(N)降到 O(1)。使用三个整数cols、dia1和 dia2分别记录每一列以及两个方向的每条斜线上是否有皇后,每个整数有 N个二进制位。用 0 代表可以放置皇后的位置,1 代表不能放置皇后的位置。
public List<List<String>> solveNQueens(int n) {
List<List<String>> sol =new ArrayList<List<String>>();
int[] queens=new int[n];
Arrays.fill(queens,-1);
back(sol,queens,n,0,0,0,0);
return sol;
}
public void back(List<List<String>> sol,int[] queens,int n,int row,int col,int dia1,int dia2){
if(row==n){
List<String> board=gen(queens,n);
sol.add(board);
}else{
int ava=((1<<n)-1)&(~(col|dia1|dia2));
while(ava!=0){
int pos=ava&(-ava);
ava=ava&(ava-1);
int cols=Integer.bitCount(pos-1);
queens[row]=cols;
back(sol,queens,n,row+1,col|pos,(dia1|pos)<<1,(dia2|pos)>>1);
queens[row]=-1;
}
}
}
public List<String> gen(int[] queens,int n){
List<String> board =new ArrayList<String>();
for(int i=0;i<n;i++){
char[] row=new char[n];
Arrays.fill(row,'.');
row[queens[i]]='Q';
board.add(new String(row));
}
return board;
}
复杂度分析
时间复杂度:O(N!),其中 N是皇后数量。
空间复杂度:O(N)。