51. N-Queens
给n x n棋盘,求有多少种n个皇后互相不攻击的摆法,处于同一条竖线,横线对角线的皇后可以攻击到对方。
使用dfs遍历,逐行进行尝试,找到合适位置就取下一行继续,没有的话就回溯到上一行重新找个位置,主要是这题格式比较烦人:
public List<List<String>> solveNQueens(int n) {
char[][] chess = new char[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
chess[i][j] = '.';
}
}
help(n, chess, 0);
return res;
}
List<List<String>> res = new ArrayList<>();
public void help(int n, char[][] once, int row) {
if (row == n) {
List<String> str = new ArrayList<>();
StringBuffer s = new StringBuffer("");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
s.append(once[i][j]);
}
str.add(s.toString());
s = new StringBuffer("");
}
res.add(str);
return;
}
for (int i = 0; i < n; i++) {
if (valid(once, row, i)) {
once[row][i] = 'Q';
help(n, once, row+1);
once[row][i] = '.';
}
}
}
public boolean valid(char[][] once, int row, int col) {
int diff = row - col, sum = row + col;
for (int i = 0; i < once.length; i++) {
if (i != row && once[i][col] == 'Q') return false; //同列存在
if (i != col && once[row][i] == 'Q') return false; //同行存在
if (i - diff >= 0 && i - diff < once.length && i != row) {
if (once[i][i-diff] == 'Q')
return false;
}
if (sum - i >= 0 && sum-i <once.length && i != row) {
if (i != row && once[i][sum - i] == 'Q')
return false;
}
}
return true;
}
52. N-Queens II
问一个nxn的棋盘有多少种n个皇后的摆法。
和上题几乎一样,只是这题只问数量,不用列出所有摆法,所以用上题的方法虽然可解,但太慢了,需要针对性优化一下:
- 只需要记住每行的皇后所在列数就行,所以用一个一维数组记录
- 接下来的东西其实和上题差不多,只是在验证位置是否合法那里有些许不同
public int totalNQueens(int n) {
int[] position = new int[n];
help(n, position, 0);
return res;
}
int res = 0;
public void help(int n, int[] position, int row) {
if (row == n) {
res++;
return;
}
for (int i = 0; i < n; i++) {
if (valid(position, row, i)) {
position[row] = i;
help(n, position, row+1);
}
}
}
public boolean valid(int[] position, int row, int col) {
//这里只用循环到当前行就行了,后面的如果继续循环反而会因为position元素的值的原因造成错误
for (int i = 0; i < row; i++) {
if (position[i] == col) return false; //列检查
if (position[i] + i == row + col || position[i] - i == col - row)
return false;
}
return true;
}