最近在刷Leetcode,遇到了N皇后的问题。去网上搜了下,发现了一个用位运算求解可行解个数的非常简单的方法(点击这里查看)。博主在里面添加了非常详细的注释和解释,只要仔细研究一下,相信每个人都能看懂。
LeetCode 52题只要求输出可行解的个数,用上面博主的代码便可轻松通过。52题的AC代码如下:(注释已删除,可查看上面博主的注释)
class Solution {
public:
int totalNQueens(int n) {
limit = (1 << n) - 1;
return nQueens(0, 0, 0);
}
private:
int nQueens(int res, int ld, int rd)
{
if (res != limit)
{
int pos = limit & ~(res | ld | rd);
int result = 0;
while (pos)
{
int p = pos & -pos;
pos -= p;
result += nQueens(res + p, (ld + p) << 1, (rd + p) >> 1);
}
return result;
}
return 1;
}
int limit;
};
但是51题需要求出所有的可行解,看了很多博客好像都是用普通的枚举+约束来做的(这篇博客的约束函数写得非常简单易懂,可以看一下),但是没有看到用位运算来解决的。于是尝试着改了一下上面的代码,发现只需要做很小的变动就可以了。51题的AC代码如下:
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
limit = (1 << n) - 1;
vector<string> vec(n, string(n, '.'));// 初始化一个全是'.'的vector,用来保存尝试结果
nQueue(0, 0, 0, 0, vec);// 参数k初始化为0,表示第0行
return result;
}
private:
// 第4个参数k表示尝试的行数
void nQueue(long res, long ld, long rd, int k, vector<string>& vec)
{
if (res != limit)
{
int pos = limit & ~(res | ld | rd);
while (pos)
{
int p = pos & -pos;
pos -= p;
/**
* pos = 2^t0 + 2^t1 + 2^t2 + ... (t0 < t1 < t2 < ...)
* 则p = 2^t0,log2(p) = t0
* t0则为可放置皇后的列
*/
vec[k][log2(p)] = 'Q';// 在第k行第t0列尝试放置一个皇后
nQueue(res + p, (ld + p) << 1, (rd + p) >> 1, k + 1, vec);// k + 1 : 继续进行下一行的尝试
vec[k][log2(p)] = '.';// 因为参数是引用,所以此处要复原vec
}
}
else result.push_back(vec);// 找到一个解,添加到结果中
}
vector<vector<string>> result;
int limit;
};
位运算的代码提交后,Run Time只用了3ms,试了下其他的方法,都在15ms左右,速度确实提高了很多。如果大家有更好的方法,欢迎交流~