题目链接:
https://leetcode-cn.com/problems/n-queens/
皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
示例 1:
- 输入:n = 4
- 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
- 解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:
- 输入:n = 1
- 输出:[["Q"]]
都知道n皇后问题是回溯算法解决的经典问题,但是用回溯解决多了组合、切割、子集、排列问题之后,遇到这种二维矩阵还会有点不知所措。
首先来看一下皇后们的约束条件:
- 不能同行
- 不能同列
- 不能同斜线
把题目抽象成树结构可能更好理解一些:
利用递归四部曲:
递归作用:在第layer层(layer从0算起)寻找合适的Q的放法
递归参数:n代表n皇后,layer代表当前的层数
终止条件:layer==n表示到底了
单层逻辑:在这一层从0开始取,取的时候判断位置的合理性,取完这一层再取下一层
回溯算法的话记得在这一层操作完之后要初始化状态量哦
class Solution {
char[][] chessboard = null;//棋盘
List<List<String>> result = null;//存放所有最后结果
List<String> path = null;//存放当前合理结果
void solveNQueens1(int n, int layer){
//递归作用:在第layer层(layer从0算起)寻找合适的Q的放法
//参数:n代表n皇后,layer代表当前的层数
//终止条件:layer==n表示到底了
//单层逻辑:在这一层从0开始取,取的时候判断位置的合理性,取完这一层再取下一层
if(layer == n){
for(char[] x: chessboard)
path.add(new String(x));
result.add(new ArrayList(path));
path.clear();
return;
}
for(int i = 0; i < n; i++){
if(isValid(layer, i, n)){//在同一层取下一个
chessboard[layer][i] = 'Q';
solveNQueens1(n, layer + 1);//取下一层
chessboard[layer][i] = '.';//回溯
}
}
}
boolean isValid(int x, int y, int n){//x是行,y是列
//判断chessboard中(x, y)位置放置Q合不合理
for(int i = 0; i < y; i++)//判断同一行
if(chessboard[x][i] == 'Q') return false;
for(int i = 0; i < x; i++)//判断同一列
if(chessboard[i][y] == 'Q') return false;
for(int i = x - 1, j = y - 1; i >= 0 && j >= 0; i--, j--)//判断左上方
if(chessboard[i][j] == 'Q') return false;
for(int i = x - 1, j = y + 1; i >= 0 && j < n; i--, j++)//判断右上方
if(chessboard[i][j] == 'Q') return false;
return true;
}
public List<List<String>> solveNQueens(int n) {
result = new ArrayList<>();
path = new ArrayList<>();
chessboard = new char[n][n];
for(char[] x : chessboard)//填充棋盘
Arrays.fill(x, '.');
solveNQueens1(n, 0);
return result;
}
}