LeetCode 51. N-Queens和52. N-Queens II的位运算解法

最近在刷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左右,速度确实提高了很多。如果大家有更好的方法,欢迎交流~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值