1. 程式人生 > >LeetCode 51. N-Queens和52. N-Queens II的位運算解法

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左右,速度確實提高了很多。如果大家有更好的方法,歡迎交流~