51. N皇后
51. N 皇后 - 力扣(LeetCode)
代码随想录 (programmercarl.com)
这就是传说中的N皇后? 回溯算法安排!| LeetCode:51.N皇后_哔哩哔哩_bilibili
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将
n
个皇后放置在n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。给你一个整数
n
,返回所有不同的 n 皇后问题 的解决方案。每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中
'Q'
和'.'
分别代表了皇后和空位.示例 1:
输入:n = 4 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] 解释:如上图所示,4 皇后问题存在两个不同的解法。示例 2:
输入:n = 1 输出:[["Q"]]提示:
1 <= n <= 9
其实回溯算法搜索过的位置就是一个棋盘。
回溯三部曲:
1、确定参数:
定义全局变量二维数组result来收集最终结果,n是棋盘的大小,row来记录遍历到棋盘第几层:
public void backTrack(int n, int row, char[][] chessboard) {
}
2、确定终止条件:
当棋盘递归到叶子节点的时候,说明找到了一个符合条件的结果,收集叶子节点的值并返回:
// 如果当前行数等于 n,说明找到了一个解,将其转换为字符串列表并添加到结果列表中
if (row == n) {
res.add(Array2List(chessboard));
return;
3、确定单层搜索的逻辑:
// 遍历当前行的所有列
for (int col = 0; col < n; ++col) {
// 如果当前位置可以放置皇后
if (isValid(row, col, n, chessboard)) {
// 在当前位置放置皇后
chessboard[row][col] = 'Q';
// 继续向下一行搜索
backTrack(n, row + 1, chessboard);
// 回溯,将当前位置重新设为 '.'
chessboard[row][col] = '.';
}
}
验证棋盘是否符合要求:
1、皇后不能同行
2、皇后不能同列
3、不能同斜线
// 定义一个公有方法 isValid,用于检查当前位置是否可以放置皇后
public boolean isValid(int row, int col, int n, char[][] chessboard) {
// 检查当前列是否有皇后
for (int i = 0; i < row; ++i) { // 相当于剪枝
if (chessboard[i][col] == 'Q') {
return false;
}
}
// 检查45度对角线是否有皇后
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
// 检查135度对角线是否有皇后
for (int i = row - 1, j = col + 1; i >= 0 && j <= n - 1; i--, j++) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
return true;
}
综合代码:
// 定义一个名为 Solution 的类
class Solution {
// 声明一个成员变量 res,类型为 List<List<String>>,用于存储解决N皇后问题的结果
List<List<String>> res = new ArrayList<>();
// 定义一个公有方法 solveNQueens,接收一个整数参数 n,返回解决N皇后问题的结果
public List<List<String>> solveNQueens(int n) {
// 创建一个大小为 n*n 的字符数组表示棋盘,初始化为 '.'
char[][] chessboard = new char[n][n];
for (char[] c : chessboard) {
Arrays.fill(c, '.');
}
// 调用 backTrack 方法进行回溯搜索解决N皇后问题
backTrack(n, 0, chessboard);
// 返回解决N皇后问题的结果
return res;
}
// 定义一个公有方法 backTrack,用于回溯搜索解决N皇后问题
public void backTrack(int n, int row, char[][] chessboard) {
// 如果当前行数等于 n,说明找到了一个解,将其转换为字符串列表并添加到结果列表中
if (row == n) {
res.add(Array2List(chessboard));
return;
}
// 遍历当前行的所有列
for (int col = 0; col < n; ++col) {
// 如果当前位置可以放置皇后
if (isValid(row, col, n, chessboard)) {
// 在当前位置放置皇后
chessboard[row][col] = 'Q';
// 继续向下一行搜索
backTrack(n, row + 1, chessboard);
// 回溯,将当前位置重新设为 '.'
chessboard[row][col] = '.';
}
}
}
// 定义一个公有方法 Array2List,用于将字符数组转换为字符串列表
public List Array2List(char[][] chessboard) {
List<String> list = new ArrayList<>();
// 将字符数组转换为字符串并添加到列表中
for (char[] c : chessboard) {
list.add(String.copyValueOf(c));
}
return list;
}
// 定义一个公有方法 isValid,用于检查当前位置是否可以放置皇后
public boolean isValid(int row, int col, int n, char[][] chessboard) {
// 检查当前列是否有皇后
for (int i = 0; i < row; ++i) { // 相当于剪枝
if (chessboard[i][col] == 'Q') {
return false;
}
}
// 检查45度对角线是否有皇后
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
// 检查135度对角线是否有皇后
for (int i = row - 1, j = col + 1; i >= 0 && j <= n - 1; i--, j++) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
return true;
}
}