今天做了leetcode中两道关于N皇后的题目:
51. N-Queens
52. N-Queens II
这是回溯法的经典应用,自己不太会做…主要是研究了下别人的思路,然后自己写了写~
N-Queens II
Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.
(1)简单易懂版本(或者利用循环将其改为非递归形式)
public class Solution {
int sum = 0;
public int totalNQueens(int n) {
int[] y = new int[n];//解向量,代表皇后被放置在i+1行y[i]+1列(0~n-1/1~n)
backtracking(1,n,y);
return sum;
}
private boolean place(int row, int[] y){
//row介于1-n之间,代表目前在讨论第几行的皇后
for(int i=0;i<row-1;i++){
//如果当前的皇后和之前的皇后位于同一列或者对角线(行差等于列差)
if(y[i]==y[row-1] || Math.abs(i-row+1)==Math.abs(y[i]-y[row-1])) return false;
}
return true;
}
//回溯,需要递归调用
private void backtracking(int row,int n, int[] y){
if(row > n) sum++;
else{
//在第row行选择合适的一列把第row个皇后放下
for(int i=0;i<n;i++){
y[row-1] = i;
if(place(row,y)) backtracking(row+1,n,y);//位置合适,则开始考虑下一行
}
//运行至此,表示没有找到合适的位置,将会返回到上一级的backtracking语句行,
//重新摆放上一个皇后,继续寻找可能得解
}
}
}
(2)在discuss里看到一种利用位运算降低空间复杂度和时间复杂度的算法,之前也使用过这种手段,即利用每一位(’0’或者’1’)表示一种状态,每次都在更新。
public class Solution {
int sum = 0;
public int totalNQueens(int n) {
backtracking(0,n,0,0,0);
return sum;
}
//回溯,需要递归调用
//row: 目前讨论的是在第row行放置queen(row介于0~n-1)
//n: 一共需要放置n个queen
//以棋盘左下角为原点坐标
//colHasQueen:标记此行之前的哪些column已经放置了皇后,
// 如有放置在(r,c)坐标上的皇后则colHasQueen[c]=1;
//diagHasQueen:标记此行之前的哪些主对角线已经放置了皇后,
// 如有放置在(r,c)坐标上的皇后则diagHasQueen[n-1+r-c]=1;->棋盘格子向对角线做垂线映射得到
//antidiagHasQueen:标记此行之前的哪些副对角线已经放置了皇后,
// 如有放置在(r,c)坐标上的皇后则antidiagHasQueen[r+c]=1;->棋盘格子向其做垂线映射得到
private void backtracking(int row,int n, int colHasQueen, int diagHasQueen, int antidiagHasQueen){
if(row == n) sum++;
else{
for(int i=0;i<n;i++){
boolean isColSafe = ((1<<i)&colHasQueen)==0;
boolean isDiagSafe = ((1 << (n - 1 + row - i)) & diagHasQueen)==0;
boolean isAntiDiagSafe = ((1 << (row + i)) & antidiagHasQueen)==0;
if(isColSafe&&isDiagSafe&&isAntiDiagSafe){
backtracking(row+1, n, (1<<i)|colHasQueen, ((1 << (n - 1 + row - i)) | diagHasQueen), (1 << (row + i)) | antidiagHasQueen);
}
}
//运行至此,表示没有找到合适的位置,将会返回到上一级的backtracking语句行,
//重新摆放上一个皇后,继续寻找可能得解
}
}
}
51. N-Queens
Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens’ placement, where ‘Q’ and ‘.’ both indicate a queen and an empty space respectively.
For example,
There exist two distinct solutions to the 4-queens puzzle:
[
[“.Q..”, // Solution 1
“…Q”,
“Q…”,
“..Q.”],
[“..Q.”, // Solution 2
“Q…”,
“…Q”,
“.Q..”]
]
写完上面那个,下面的就好些一点啦~重点是要选好数据结构去存储solutions。
public class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> result = new ArrayList<List<String>>();
char[][] curSolution = new char[n][n];
backtracking(0,n,0,0,0,result, curSolution);
return result;
}
private void backtracking(int row,int n, int colHasQueen, int diagHasQueen, int antidiagHasQueen, List<List<String>> result, char[][] curSolution){
if(row == n){
List<String> cur = new ArrayList<String>();
for(char[] tmp:curSolution){
cur.add(String.valueOf(tmp));
}
result.add(cur);
}
else{
for(int i=0;i<n;i++){
boolean isColSafe = ((1<<i)&colHasQueen)==0;
boolean isDiagSafe = ((1 << (n - 1 + row - i)) & diagHasQueen)==0;
boolean isAntiDiagSafe = ((1 << (row + i)) & antidiagHasQueen)==0;
if(isColSafe&&isDiagSafe&&isAntiDiagSafe){
curSolution[row][i] = 'Q';
backtracking(row+1, n, (1<<i)|colHasQueen, ((1 << (n - 1 + row - i)) | diagHasQueen), (1 << (row + i)) | antidiagHasQueen, result, curSolution);
curSolution[row][i]='.';
}
}
}
}
}
要学的东西太多了…希望自己每天多打打鸡血,不要像以前那样懒…