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;}
}