问题描述
我的解法
方法一:暴力枚举
思路参考DFS(递归枚举所有排列,复杂度为O(N2))
class Solution {
public:
bool hash[10]={false};
int p[10]={0};
void solve(vector<vector<string>> &result,int &n, int index){
//边界判断
if(index==n+1){
//flag判断当前排列合法
bool flag=true;
//此处的循环意思是,检查已有的排列是不是合法
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(abs(i-j)==abs(p[i]-p[j])){
flag=false;
}
}
}
if(flag){
//此时p[]为n列皇后所在的行号
vector<string> res;
for(int j=1;j<index;j++){
string s;
for(int i=1;i<index;i++){
if(i!=p[j]){
s.append(".");
}else{
s.append("Q");
}
}
res.push_back(s);
}
result.push_back(res);
}
return;
}
for(int i=1;i<=n;i++){
if(hash[i]==false){
//此处不管i放在p[index]合不合法,先放上再说
p[index]=i;
hash[i]=true;
solve(result,n,index+1);
hash[i]=false;
}
}
}
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> result;
solve(result,n,1);
return result;
}
};
方法二:回溯法(剪枝)
回溯法,或者说是DFS的剪枝算法,如果某种情况到某个深度时已经冲突,则直接回溯,减少计算。
class Solution {
public:
bool hash[10]={false};
int p[10]={0};
void solve(vector<vector<string>> &result,int &n, int index){
//边界判断
if(index==n+1){
//此时p[]为n列皇后所在的行号
vector<string> res;
for(int j=1;j<index;j++){
string s;
for(int i=1;i<index;i++){
if(i!=p[j]){
s.append(".");
}else{
s.append("Q");
}
}
res.push_back(s);
}
result.push_back(res);
return;
}
//第index列,列是根据递归依次增长的,行是用hash表标记的,对角线再次判断
for(int i=1;i<=n;i++){
//第i行还没有皇后
if(hash[i]==false){
bool flag = true;
//此处的循环意思是,如果i放在p[index]不合法,那就不放
for(int pre=1;pre<index;pre++){
//第index列皇后的行号为i,第pre列皇后的行号为p[pre]
if(abs(index-pre)==abs(i-p[pre])){
flag=false;//与之前的皇后在同一对角线
break;
}
}
if(flag){
p[index]=i;
hash[i]=true;
solve(result,n,index+1);
hash[i]=false;
}
}
}
}
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> result;
solve(result,n,1);
return result;
}
};