注:
题目:
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
皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。
题解:
思路
都知道n皇后问题是回溯算法解决的经典问题,但是用回溯解决多了组合、切割、子集、排列问题之后,遇到这种二位矩阵还会有点不知所措。
首先来看一下皇后们的约束条件:
- 不能同行
- 不能同列
- 不能同斜线
确定完约束条件,来看看究竟要怎么去搜索皇后们的位置,其实搜索皇后的位置,可以抽象为一棵树。下面我用一个3 * 3 的棋牌,将搜索过程抽象为一颗树,如图:
从图中,可以看出,二维矩阵中矩阵的高就是这颗树的高度,矩阵的宽就是树形结构中每一个节点的宽度。
那么我们用皇后们的约束条件,来回溯搜索这颗树,只要搜索到了树的叶子节点,说明就找到了皇后们的合理位置了。
验证棋牌是否合法
- 不能同行
- 不能同列
- 不能同斜线 (45度和135度角)
如果令行作为递归的深度,则不需要在同行进行检查,因为在单层搜索的过程中,每一层递归,只会选for循环(也就是同一行)里的一个元素,所以不用去重了。
复杂度分析
时间复杂度:O(N!),其中 N 是皇后数量。
空间复杂度:O(N),其中 N 是皇后数量。空间复杂度主要取决于递归调用层数、记录每行放置的皇后的列下标的数组以及三个集合,递归调用层数不会超过 N,数组的长度为 N,每个集合的元素个数都不会超过 N。
class Solution {
public:
vector<vector<string>> result;
bool judge(vector<string>& path,int row,int col,int n){
//检查列
for(int i=0;i<row;i++){
if(path[i][col]=='Q'){
return false;
}
}
//检查左上角
for(int i=row,j=col;i>=0&&j>=0;i--,j--){
if(path[i][j]=='Q'){
return false;
}
}
//检查右上角
for(int i=row,j=col;i>=0&&j<n;i--,j++){
if(path[i][j]=='Q'){
return false;
}
}
return true;
}
void backtracking(vector<string>& path,int row,int n){
if(row==n){
result.push_back(path);
return ;
}
for(int col=0;col<n;col++){
if(judge(path,row,col,n)==true){
path[row][col]='Q';
backtracking(path,row+1,n);
path[row][col]='.';
}
}
}
vector<vector<string>> solveNQueens(int n) {
vector<string> path(n,string(n,'.'));
backtracking(path,0,n);
return result;
}
};