leetcode 52.N-Queens II【递归、位运算】【hard】|刷题打卡

221 阅读2分钟

一、题目描述:

leetcode 52.N-Queens II: n皇后问题,要求返回指定格式的二维列表,其中“Q”表示皇后的位置,“.”表示皇后不在的位置。

二、思路分析:

1.类别

递归、回溯、位运算、动态规划

2.普通递归思路

N×NN\times N 的格子中摆N个皇后,第i个皇后就摆在i行,可以用一个一维数组表示record [i] 表示第i行的存储皇后的位置(列数)。如果用普通的递归方法,简单的代码如下: 设置一个循环的变量i,i相当于行指针,当i到达最后一行时,返回1,对每一列都进行尝试,如果isValid函数为真,那么j能够被放置。累加调用递归函数尝试放置下一行的结果,这样就会把所有的情况都累加起来了。 isValid()函数会讨论两种情况,一种是共列,一种是在对角线上。当两个皇后共对角线时,它们行的差值等于列的差值。

int process1(int i, int* &record int n){
    if(i==n)
        return 1;
    for(int j=0;j<n;j++) //尝试每一列
    {
        if(isValid(record,i,j)){
            record[i]=j;
            res+=process1(i+1,record,n);
        }
    }
}

bool isValid(int* &record,int i, int j){
//共行 c==d
//共斜线abs(a-c)==abs(b-d);
}

3.位运算解法

位运算的解法在leetcode 51.N-Queens【递归、位运算】【hard】中有比较详细的解释。如果做了51再做52的话,其实只要把返回值从二维数组改为返回二维数组的大小即可。具体代码如下,尝试后其实速度并不慢,但是占用的空间较大。

class Solution {
public:

    void reculSolution(int n, int limit, int lLim, int rLim, int colLim,
                       vector<int> &pos, vector<vector<int>> &result)
    {

        int avaPos = limit & ~(colLim | lLim | rLim);
        int mostRight;
        while (avaPos != 0)
        {
            mostRight = avaPos & (~avaPos + 1);
            avaPos = avaPos - mostRight;
            pos.push_back(mostRight);
            reculSolution(n, limit, (lLim | mostRight) << 1, (unsigned int)(rLim | mostRight) >> 1,
                          colLim | mostRight, pos, result);
            if (pos.size() == n)
                result.push_back(pos);
            pos.pop_back();
        }
    }
    int totalNQueens(int n) {
        int limit = n == 32 ? -1 : (1 << n) - 1;
        int lLim = 0, rLim = 0, colLim = 0; //左对角线限制、右对角线限制、列限制
        vector<vector<int>> result;
        vector<int> pos;
        reculSolution(n, limit, lLim, rLim, colLim, pos, result);

        return result.size();
    }
};

因此可以考虑将原来的递归代码进行一些修改,结合普通递归的思路,函数的返回值为int, 累加调用函数后的返回值。具体代码在第三部分,能够明显地看到空间复杂度降低了。

三、AC 代码:

class Solution {
public:

    int reculSolution(int limit, int lLim, int rLim, int colLim)
    {
        int result=0;
        if(colLim==limit)
            return 1;
        int avaPos = limit & ~(colLim | lLim | rLim);
        int mostRight;
        while (avaPos != 0)
        {
            mostRight = avaPos & (~avaPos + 1);
            avaPos = avaPos - mostRight;
            result+=reculSolution(limit, (lLim | mostRight) << 1, 
                                  (unsigned int)(rLim | mostRight) >> 1, 
                                  colLim | mostRight);
        }
        return result;
    }
    int totalNQueens(int n) {
        int limit = n == 32 ? -1 : (1 << n) - 1;
        int lLim = 0, rLim = 0, colLim = 0; //左对角线限制、右对角线限制、列限制
        int result=reculSolution(limit, lLim, rLim, colLim);
        return result;
    }
};

四、总结

这一题和leetcode 51.N-Queens【递归、位运算】【hard】能够放在一起对比,也是因为从暴力递归到位运算的这一思路值得借鉴和思考。并且从递归还能够直接转化成动态规划来做,后续再填坑吧。


本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情