【LeetCode每日一题】[困难]52. N皇后 II
52. N皇后 II
题目来源
算法思想:回溯
题目:
题目分析
java代码
class Solution {
boolean[] columns;//用来标记列是否有Q
boolean[] diagonals1;//用来标记正对角线是否有Q
boolean[] diagonals2;;//用来标记反对角线是否有Q
int count = 0;//用于计数,有多少种方法
public int totalNQueens(int n) {
//初始化
columns = new boolean[n];//行列长度范围: 0到n-1
//正对角线范围i-j: -(n-1)到n-1,
//利用i-j+n映射到0-2n范围进行存放, 初始化用2n长度来存放
diagonals1 = new boolean[n * 2];
//反对角线范围i+j: 0到2*(n-1)
//初始化用2n长度来存放
diagonals2 = new boolean[n * 2];
backtrack(n, 0);//回溯
return count;//返回计数
}
private void backtrack(int n, int i) {
//如果递归到了n层,说明前面n-1层都已经填写好了,即找到了答案,计数++;
if (i == n) {
count++;
return;
}
for (int j = 0; j < n; j++) {
//从0开始在i行尝试j列
if (columns[j] == true) {
//列重复,尝试下一个可能列j
continue;
}
int diagonal1 = i - j + n;//计算正对角线
int diagonal2 = i + j;//计算反对角线
if (diagonals1[diagonal1] == true) {
//正对角线重复,尝试下一个可能列j
continue;
}
if (diagonals2[diagonal2] == true) {
//反对角线重复,尝试下一个可能列j
continue;
}
//以上条件均没有重复,即可以在j列填入Q
columns[j] = true;//将列设置占有
diagonals1[diagonal1] = true;//将正对角线设置占有
diagonals2[diagonal2] = true;//将反对角线设置占有
backtrack(n, i+1);//向下递归,尝试下一行的Q的填法
//递归结束,将j列取消填写,尝试下一个j
columns[j] = false;//将列设置未占有
diagonals1[diagonal1] = false;//将正对角线设置未占有
diagonals2[diagonal2] = false;//将反对角线设置未占有
}
}
}
51. N 皇后
题目来源
算法思想:回溯
题目:相比于52题,这个要输出棋盘;
思路:同上,只是要将棋盘保存下来
java代码
class Solution {
boolean[] columns;//用来标记列是否有Q
boolean[] diagonals1;//用来标记正对角线是否有Q
boolean[] diagonals2;;//用来标记反对角线是否有Q
char[][] path;//用来存放棋盘
List<List<String>> res = new ArrayList<List<String>>();//返回答案
public List<List<String>> solveNQueens(int n) {
//初始化
columns = new boolean[n];//行列长度范围: 0到n-1
//正对角线范围i-j: -(n-1)到n-1,
//利用i-j+n映射到0-2n范围进行存放, 初始化用2n长度来存放
diagonals1 = new boolean[n * 2];
//反对角线范围i+j: 0到2*(n-1)
//初始化用2n长度来存放
diagonals2 = new boolean[n * 2];
//初始化棋盘
path = new char[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
path[i][j] = '.';
}
}
backtrack(n, 0);
return res;
}
private void backtrack(int n, int i) {
//如果递归到了n层,说明前面n-1层都已经填写好了,即找到了答案,计数++;
if (i == n) {
List<String> tmp = new ArrayList<>();//String列表,放入棋盘
for (int j = 0; j < n; j++) {
tmp.add(new String(path[j]));//将path数组每行变成一个字符串
}
res.add(tmp);//将整个棋盘tmp放入res中
return;
}
for (int j = 0; j < n; j++) {
//从0开始在i行尝试j列
if (columns[j] == true) {
//列重复,尝试下一个可能列j
continue;
}
int diagonal1 = i - j + n;//计算正对角线
int diagonal2 = i + j;//计算反对角线
if (diagonals1[diagonal1] == true) {
//正对角线重复,尝试下一个可能列j
continue;
}
if (diagonals2[diagonal2] == true) {
//反对角线重复,尝试下一个可能列j
continue;
}
//以上条件均没有重复,即可以在j列填入Q
path[i][j] = 'Q';
columns[j] = true;//将列设置占有
diagonals1[diagonal1] = true;//将正对角线设置占有
diagonals2[diagonal2] = true;//将反对角线设置占有
backtrack(n, i+1);//向下递归,尝试下一行的Q的填法
//递归结束,将j列取消填写,尝试下一个j
path[i][j] = '.';
columns[j] = false;//将列设置未占有
diagonals1[diagonal1] = false;//将正对角线设置未占有
diagonals2[diagonal2] = false;//将反对角线设置未占有
}
}
}