题目:Now, instead outputting board configurations, return the total number of distinct solutions.
思路:回溯法和二进制法
二进制法可能是目前最快的算法。
本质上来讲,这两题没啥区别。只是再写一遍。
首先我需要判断是否合适,行不需要判断,只需要判断列的和两个对角线的。
判断列是在某一列,就1<<colIndex,这样,我每次只需要和原来的colflag-and一下,比如原来是11000000,现在来了一个新的00001000,这个时候and一下是0,说明有效。至于两条对角线,使用同样的方法。只不过在标志是哪条对角线,使用了一些技巧。
接下来就是满足条件,就更新,方法是并上原来的状态。
取消的时候就是一个数学逻辑变换。
这里的queenHelper函数的一个变换就是,当满足8个的时候,返回1,原来是存入堆栈。在程序中一个关键的就是满足条件count要加上后来start+1的情况。
代码:
//切记,本题目还有一种位比较法,可以很快输出有多少个。
class Solution1 {
private:
//https://leetcode.com/problems/n-queens-ii/
int colFlag;//代表列
int diagFlag1;//index=i+j
int diagFlag2;//index=n-1+i-j
bool isValid(int rowIndex,int colIndex,int n){
//行不需要判断,因为我是按照行走的
//为0说明有效
if( (1<<colIndex)&colFlag ){
//为1 无效
return false;
}
if( (1<<(rowIndex+colIndex))&diagFlag1 ){
return false;
}
if( (1<<(n-1+rowIndex-colIndex) ) & diagFlag2 ){
return false;
}
return true;
}
void setFlag(int rowIndex,int colIndex,int n){
colFlag |=(1<<colIndex);
diagFlag1 |=(1<<(rowIndex+colIndex));
diagFlag2 |=(1<<(n-1+rowIndex-colIndex));
}
void unsetFlag(int rowIndex, int colIndex, int n) {
colFlag &= ~(1 << colIndex);
diagFlag1 &= ~(1 << (rowIndex + colIndex));
diagFlag2 &= ~(1 << (n + rowIndex - colIndex - 1));
}
int queenHelper(int n, vector<string> &answer, vector<vector<string> > &result) {
int rowIndex = answer.size();
if (rowIndex == n) {
result.push_back(answer);
return 1;
}
int count=0;
answer.push_back(string(n, '.'));
for (int i = 0; i < n; i++) {
if (isValid(rowIndex, i, n)) {
setFlag(rowIndex, i, n);
answer.back()[i] = 'Q';
count+=queenHelper(n, answer, result);//每一次迭代或者说是递归调用会有新的count生成,但是只是返回值,最终还是
//所有的count值。
answer.back()[i] = '.';
unsetFlag(rowIndex, i, n);
}
}
answer.pop_back();
return count;
}
public:
int totalNQueens(int n) {
// https://oj.leetcode.com/problems/n-queens/
colFlag = diagFlag1 = diagFlag2 = 0;
vector<vector<string> > result;
vector<string> answer;
return queenHelper(n, answer, result);
}
};