N-Queens II
题目: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); } };