现在的位置: 首页 > 综合 > 正文

N-Queens II — leetcode

2018年10月18日 ⁄ 综合 ⁄ 共 1643字 ⁄ 字号 评论关闭

Follow up for N-Queens problem.

Now, instead outputting board configurations, return the total number of distinct solutions.

算法

利用permutation中使用swap的思路,可以快速满足列条件的限制。

这样,在检查合法性时,只需要检查是否满足对角线的限制即可。

此算法在leetcode上的实际的执行时间为4ms。

class Solution {
public:
    int totalNQueens(int n) {
        int sum = 0;
        vector<int> solution;
        for (int i=0; i<n; i++)
                solution.push_back(i);

        helper(solution, 0, sum);
        return sum;
    }

    void helper(vector<int> &solution, int start, int &sum) {
        if (start == solution.size()) {
                ++sum;
                return;
        }

        for (int i=start; i<solution.size(); i++) {
                swap(solution[i], solution[start]);
                if (isValid(solution, start)) {
                        helper(solution, start+1, sum);
                }
                swap(solution[i], solution[start]);
        }
    }

    bool isValid(vector<int> &solution, int start) {
        for (int i=start-1; i>=0; --i) {
                if (start-i == abs(solution[start]-solution[i]))
                        return false;
        }
        return true;
    }
};

算法二:

基于回溯法。

特点,利用3个数组,分别记录剩下的列,以及由左对角线,右对角线的限制。

这样在回溯时,可以快速确定某个位置,是否可用。

此算法在leetcode上实际执行时间为3ms。

注,这里选择vector<char>,而不是vector<bool>。这是基于性能考虑,如果选择vector<bool>,执行时间会达到8ms。

原因,则是因为stl 对vector<bool>作了比特化的特化,虽说是省了空间,但却是以时间为代价。

class Solution {
public:
    int totalNQueens(int n) {
        int sum = 0;
        vector<int> cl; //  column
        vector<char> ld(n*2);  //left diagonal
        vector<char> rd(n*2); // right diagonal

        for (int i=0; i<n; i++)
                cl.push_back(i);

        helper(cl, 0, ld, 0, rd, n, sum);
        return sum;
    }

    void helper(vector<int> &cl, int start_cl, vector<char> &ld, int start_ld, vector<char> &rd, int start_rd, int &sum) {
        if (start_cl == cl.size()) {
                ++sum;
                return;
        }

        for (int i=start_cl; i<cl.size(); i++) {
                const int ldi = start_ld + cl[i];
                const int rdi = start_rd + cl[i];

                if (!ld[ldi] && !rd[rdi]) {
                        ld[ldi] = rd[rdi] = true;
                        swap(cl[i], cl[start_cl]);
                        helper(cl, start_cl+1, ld, start_ld+1, rd, start_rd-1, sum);
                        swap(cl[i], cl[start_cl]);
                        ld[ldi] = rd[rdi] = false;
                }
        }
    }
};

算法二,与算法一的主要差别是:

算法二用

!ld[ldi] && !rd[rdi]
这一句代替了算法一中isValid() 函数。

抱歉!评论已关闭.