题目
设计一种算法,打印 N 皇后在 N × N 棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。
示例
输入:4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释: 4 皇后问题存在如下两个不同的解法。
[
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解题思路:回溯算法
1、从第0行开始,该行上的每一列都做判断,判断是否满足不在其他皇后的攻击范围内。
2、回溯的大框架就是for循环里dfs,此题中的分支也就是for循环的内容是确定行的每一列都要判断是否能放Queen。dfs的内容是下一行的每一列。
3、接下来就是该如何判断i,j这个位置是否可以放置Queen。对于i行前的每一行,
①如果j列有Queen,则在攻击范围内,return false。
②如果j-1,j-2....j-n列有Queen,则在攻击范围内,return false
③如果j+1,j+2....j+n列有Queen,则在攻击范围内,return false
如果都没有,则该处i,j可以放置Queen。
代码
public static List<List<String>> solveNQueens(int n) {
List<List<String>> res = new ArrayList<>();
char [][] board = new char[n][n];
init(board);
helper(res,board,0);
return res;
}
private static void helper(List<List<String>> res, char[][] board, int rowIndex) {
//终止条件:已经处理完最后一行
if (rowIndex == board.length){
res.add(generate(board));
return;
}
//dfs
//尝试往这一行的每一列上放置Queen
for (int colIndex = 0;colIndex < board.length; colIndex++) {
//此处是否可放置Queen
if (isValid(board,rowIndex,colIndex)){
board[rowIndex][colIndex] = 'Q';
helper(res,board,rowIndex + 1);
//回溯
board[rowIndex][colIndex]=',';
}
}
}
private static boolean isValid(char[][] board, int rowIndex, int colIndex) {
//判断该行前的每一行Queen的位置是否可攻击此行
//此列上是否有Queen
for (int i = 0; i < rowIndex; i++) {
if (board[i][colIndex] == 'Q') return false;
}
//左上方对角线是否有Queen
for (int i = rowIndex-1,j = colIndex -1; i >=0 && j>=0 ; rowIndex--,colIndex--) {
if (board[i][j] == 'Q') return false;
}
for (int i = rowIndex -1 , j = rowIndex + 1; i >= 0 && j>=0 ; i--,j--) {
if (board[i][j] == 'Q') return false;
}
return true;
}
private static List<String> generate(char[][] board) {
List<String> list = new ArrayList<>();
for (char [] row:board) {
StringBuffer sb = new StringBuffer();
for (char c:row) {
sb.append(c);
}
list.add(sb.toString());
}
return list;
}
private static void init(char[][] board) {
for (int i = 0; i < board.length; i++) {
Arrays.fill(board[i],'.');
}
}