【问题标题】:Better way to implement count_permutations?实现 count_permutations 的更好方法?
【发布时间】:2008-11-09 16:18:23
【问题描述】:

我需要一个函数 count_permutations() 来返回给定范围的排列数。 假设允许修改范围,并从第一个排列开始,我可以天真地将其实现为对 next_permutation() 的重复调用,如下所示:

template<class Ret, class Iter>
Ret count_permutations(Iter first, Iter last)
{
    Ret ret = 0;
    do {
        ++ret;
    } while (next_permutation(first, last));
    return ret;
}

有没有更快的方法不需要遍历所有排列来找到答案?它仍然可以假设输入可以被修改,并从第一个排列开始,但显然如果可以在没有这些假设的情况下实现它也会很棒。

【问题讨论】:

    标签: c++ algorithm math


    【解决方案1】:

    所有元素都是唯一的范围的排列数是 n!其中 n 是范围的长度。

    如果存在重复元素,您可以使用 n!/(n_0!)...(n_m!) 其中 n_0...n_m 是重复范围的长度。

    所以例如 [1,2,3] 有 3! = 6 个排列,而 [1,2,2] 有 3!/2! = 3 个排列。

    编辑: 一个更好的例子是 [1,2,2,3,3,3] 它有 6!/2!3! = 60 个排列。

    【讨论】:

    • 好的,那么如果对范围进行了排序,则需要遍历该范围才能找到重复范围的所有大小。谢谢。
    • 对于 C++,是的,如果对范围进行排序会更容易。对于像 Python 这样的动态类型语言,即使是未排序的列表也可以。即使您必须对范围进行排序,时间复杂度也是 O(n log n + n) = O(n log n),不考虑阶乘计算。
    • 注意13!太大而无法放入无符号的 32 位整数和 21!太大而无法放入无符号 64 位整数。如果您的范围包含大量元素,您可能需要使用 bignum 库来防止数学溢出。
    【解决方案2】:

    在数学中,函数 factorial !n 表示 n 个元素的排列数。

    正如 Can Berg 和 Greg 所建议的,如果集合中有重复的元素,为了将它们考虑在内,我们必须将阶乘除以每个不可区分的组(由相同元素组成的组)的排列数。

    以下实现计算范围 [first, end) 中元素的排列数。范围不需要排序。

    // generic factorial implementation...
    
    int factorial(int number) {
        int temp;
        if(number <= 1) return 1;
        temp = number * factorial(number - 1);
        return temp;
    }
    
    template<class Ret, class Iter>
    Ret count_permutations(Iter first, Iter end)
    {
        std::map<typename Iter::value_type, int> counter;
        Iter it = first;
        for( ; it != end; ++it) {
            counter[*it]++;
        }
    
        int n = 0;
        typename std::map<typename Iter::value_type, int>::iterator mi = counter.begin();
        for(; mi != counter.end() ; mi++)
            if ( mi->second > 1 )
                n += factorial(mi->second);
    
       return factorial(std::distance(first,end))/n;
    }
    

    【讨论】:

    • 这不考虑重复元素
    猜你喜欢
    • 1970-01-01
    • 2023-03-24
    • 2015-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 2011-07-07
    • 2015-06-18
    相关资源
    最近更新 更多