1. 题目描述
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/n-queens
2. 解题思路
N皇后问题:
皇后们的约束条件是:
1. 不能使同行
2. 不能是同列
3. 不能同对角线
棋盘可以看作是一个矩阵,我们在放置皇后时,为了找到一种解法,
我们从上到下,从左到右判断每个位置是否可以放置皇后。
void backtracking(参数:总行数n, 当前行数row, 棋盘二维数组) {
if (终止条件:row == n时,说明已经遍历完每一行的元素了,可以将棋盘的结果添加到返回的容器中了) {
存放结果;
return;
}
for (选择:每一行的位置) {
if(符合放置条件):
处理该节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
3. 代码
class Solution {
List<List<String>> res = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
//1. 首先对二维数组进行初始化,将每一个位置初始化为‘.’
char[][] chessboard = new char[n][n];
for(char[] c: chessboard){
Arrays.fill(c,'.');
}
//2. 进行回溯遍历
backTracking(n, 0, chessboard);
return res;
}
public void backTracking(int n, int row, char[][] chessboard){
//1. 终止条件,遍历完整个棋盘就可以保存结果了
if(row == n){
//2. 数组转化成List容器
res.add(Arrays2List(chessboard));
return;
}
//3. 单层搜索的逻辑
for(int col = 0;col < n;col++){
// 4. 判断是否可以在这个位置放置皇后
if(isValid(row, col, n, chessboard)){
chessboard[row][col] = 'Q';
backTracking(n, row+1, chessboard);
chessboard[row][col] = '.';
}
}
}
// 2. 将二维数组棋盘转为 泛型为String的List容器
public List<String> Arrays2List(char[][] chessboard){
List<String> list = new ArrayList<String>();
for(char[] c: chessboard){
list.add(String.copyValueOf(c));
}
return list;
}
// 4. 判断有效性
/**
为何没有判断同一行上是否有皇后呢?
这是因为,在单层搜索逻辑中,已经处理了这种情况,单层搜索每一行时,只可能有一个皇后。
*/
public boolean isValid(int row, int col, int n, char[][] chessboard){
//a. 判断在该位置上的同一列上是否有皇后
for(int i = 0; i < row; i++){
if(chessboard[i][col] == 'Q'){
return false;
}
}
//b. 判断左对角线上是否有皇后
for(int i = row-1,j = col-1; i >= 0 && j >=0; i--,j--){
if(chessboard[i][j] == 'Q'){
return false;
}
}
//c. 判断右对角线上是否有皇后
for(int i = row-1, j = col+1; i >= 0 && j < n;i--,j++){
if(chessboard[i][j] == 'Q'){
return false;
}
}
// 可以放置皇后
return true;
}
}