51. N 皇后 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/n-queens/submissions/
目录
方法一:采用深度探索与递归的方法进行选择
可取之处是将判断与遍历拆分成为两个子函数,这样有利于增加可读性。
同时使用一维向量xi记录第几行的皇后放在第几个位置上。
同时应该注意关于数据结构(队列,栈,向量,哈希表)作为参数传入函数时,
如果要求在void函数里面对上述类型的参数进行修改,要加”&“(比如以前的深度遍历等要对结果进行改变,所以要加”&“)
但如果不要求在void函数里对上述类型的参数进行改变,则不加”&“,表示复制一份该参数传进函数,这样你如何对函数里的参数进行改变都不影响我原参数,因为你改变的只是我的复制品。这种情况适用于该题目这种会有很多种可能的结果,但是在分叉处我要下面两条路都要走,如果以第一种方式传入参数,那么会对原参数进行改变,这样你走完第一条路你把分叉处的参数都改变了,我怎么从原来的参数走第二条路!所以要使用第二种传入参数的方式,这样相当于复制了一份传入子路的函数,同时在这条路走完不影响另一条子路的前进。
class Solution {
public:
void play(vector<vector<string>>&result, int n, vector<int>xi,int i){//i表示当前处理第几行
for(int j=0;j<n;j++){
if( judge(i,j,xi) ){
xi[i]=j;
if(i==n-1){
vector<string>one(n);
for(int p=0;p<n;p++){
string chuan(n, '.');
chuan[xi[p]]='Q';
one[p]=chuan;
}
result.push_back(one);
return;
}
play(result,n,xi,i+1);
}
}
}
bool judge(int i,int j,vector<int>xi){
for(int p=0;p<i;p++){
if( (j==xi[p]) || (abs(xi[p]-j)==abs(p-i))){return false;}
}
return true;
}
vector<vector<string>> solveNQueens(int n) {
vector<int>xi(n);
vector<vector<string>>result;//每一行里面都表示一种排列方案
play(result,n,xi,0);
return result;
}
};
方法二:使用数字的位信息
对于每一行放了一个皇后,对后面产生的影响包括“左斜线限制,右斜线限制,列限制”
通过数字的为信息表示禁止位置的变化
如果当前行放了皇后,那么算上当前行以及前面行的左限制为“(left|a)<<1)”,同理右限制“(right|a)/2”,列限制为“down|a”。
写一个二进制表示为n位“1”的int数据,limit的作用是限制位数,它从始至终都是n位1。防止左移啥的位数超出限制。
class Solution {
public:
void bianli(vector<vector<string>>&result,int limit,int left,int right,int down,int n,vector<int>one,int i){
if(down==limit){
vector<string>oneCase;
for(int i=0;i<n;i++){
string hang(n,'.');
hang[one[i]]='Q';
oneCase.push_back(hang);
}
result.push_back(oneCase);
return;
}
int pos=limit&(~(right|left|down));//pos中写0的是不行的限制,只有为1的才能填写。注意取反过了所以为1的位置是可以允许的
while(pos!=0){
int a=pos&((~pos)+1);//a提取出最后一个1
pos=pos-a;
int suanweizhi=a;
int lie=0;
while(suanweizhi!=0)
{suanweizhi=suanweizhi/2;lie++;}
//cout<<lie<<endl;
one[i]=lie-1;
bianli(result, limit , ((left|a)<<1) , ((right|a)/2) , (down|a) , n , one , i+1);
}
}
//主函数
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>>result;//if(n>31){return result;}
vector<int>one(n);
int limit=1;
for(int i=0;i<n-1;i++){
limit=1+(limit<<1);
}//写一个二进制表示为n位“1”的int数据,limit的作用是限制位数,它从始至终都是n位1
int left=0;int right=0;int down=0;//分别表示左斜线限制,右斜线限制,列限制
bianli(result,limit,left,right,down,n,one,0);
return result;
}
};
在解答过程在“one[i]=lie-1;”曾写为“one.push_back(lie-1);”但是这样带来的问题是while里面每一次都会在后面写上新的,逻辑出现错误,所以应该改变第i位的值而不是每次都添加。