题目
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
解法
套回溯模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
依次确定终止条件和递归逻辑,并回溯到上一层,N皇后重点是确定皇后摆放位置,因此要编写一个验证其位置是否合法的函数,只有合法时才继续下一步。
代码如下
List<List<String>> res = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
if (n < 1) return res;
// 数组用来存放每一次的结果,更方便操作
char[][] chessboard = new char[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
chessboard[i][j] = '.';
}
}
backTracking(n, 0, chessboard);
return res;
}
// 回溯算法
private void backTracking(int n, int row, char[][] chessboard) {
// 终止条件
if (row == n) {
// 将二维数组转换为list,放入结果集中
List<String> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < n; j++) {
sb.append(chessboard[i][j]);
}
list.add(sb.toString());
}
res.add(list);
return;
}
// 循环
for (int col = 0; col < n; col++) {
// 验证所放位置是否合理
if (isValid(n, row, col, chessboard)) {
chessboard[row][col] = 'Q';
// 递归
backTracking(n, row + 1, chessboard);
chessboard[row][col] = '.';
}
}
}
// 检测皇后的放置位置是否合理
private boolean isValid(int n, int row, int col, char[][] chessboard) {
// 不能在同一横线上
for (int i = 0; i < col; i++) {
if (chessboard[row][i] == 'Q') {
return false;
}
}
// 不能在同一条竖线上
for (int i = 0; i < row; i++) {
if (chessboard[i][col] == 'Q') {
return false;
}
}
// 不能在同一条斜线上
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
return true;
}