【问题标题】:Iterative algorithm for N choose K, without repetitions, order mattersN选择K的迭代算法,没有重复,顺序很重要
【发布时间】:2021-01-10 05:18:48
【问题描述】:

我正在寻找一种迭代算法来获得从一组 N 个元素中提取的 K 个元素的所有排列,没有重复(即没有替换),并且顺序很重要。 我知道排列的数量必须是 N!/(N-K)!。 你有什么想法吗? 谢谢。

伊万

【问题讨论】:

    标签: algorithm iteration permutation


    【解决方案1】:

    方法一:

    更简单的想法:

    由于订单很重要,我们将尝试使用next_permutation algorithmnext_permutation 函数给出下一个字典顺序唯一的排列。

    算法

    1. 创建一个大小等于原始数组大小的新数组 A。
    2. 分配最后 k 个数字 1,2,3,..k 以使 k 最后结束。将剩余数字分配为 0。
    3. 现在,在使用 next_permutation 迭代排列时,仅选择原始数组中 A > 0 的索引,保持顺序。

    正确性说明:

    由于在新创建的数组中有 N 个数字,其中 N-k 重复,总的唯一排列变为 N!/(N-k)!这给了我们想要的结果。

    示例:

    输入:X = [1,2,3], k=2

    现在,我们创建 A = [0,1,2]。

    所有排列:

    [0, 1, 2],
    [0, 2, 1],
    [1, 0, 2],
    [1, 2, 0],
    [2, 0, 1],
    [2, 1, 0].
    

    从 A[i] > 0 的原始数组中仅选择这些排列的索引 i,这将产生,

    [2,3],
    [3,2],
    [1,3],
    [1,2],
    [3,1],
    [2,1].
    

    如果您希望以上按排序顺序,请使用负数并使用 -k,-k-1,..-1 初始化前 k 个数字,其余为 0 并应用算法稍作修改,通过在原始数组中选择索引i,使得A[i]

    旁注: 如果顺序无关紧要,则在开头使用 k -1s 初始化 A,其余为 0,并使用迭代排列算法,该算法将从 N 项中生成唯一可能的 k 个选择。

    方法2:(优于方法1)

    算法:

    1. 首先选择前 K 个数字并填充到数组 A 中,它将存储原始数组中所选元素的索引。我们将其标记为第一个选择。
    2. 现在按字典顺序获取所有剩余排列。
    3. 如何根据顺序获得下一个组合?如果可能,我们将对选择进行置换,否则返回字典顺序更大的选择。

    如果排列用尽,则按词典顺序获取下一个选择的想法:

    我们考虑我们当前的组合,并找到最右边的元素 尚未达到其可能的最高值。一旦发现这个 元素,我们将其增加 1,并将最低有效值分配给 所有后续元素。

    来自:https://cp-algorithms.com/combinatorics/generating_combinations.html

    示例:

    输入:X = [1,2,3,4], k=3

    现在,我们创建 A = [0,1,2]。

    所有排列:

    [0,1,2]    // initialization
    [0,2,1]    // next permutation
    ...        // all permutations of [0,1,2]
    ...
    [2,1,0]    // reached last permutation of current selection
    [0,1,3]    // get next selection in lexicographic order as permutations are exhausted
    ...
    [3,1,0]   // reached last permutation of current selection
    [0,2,3]    // get next selection in lexicographic order as permutations are exhausted
    ...
    [3,2,0]   // reached last permutation of current selection
    [1,2,3]    // get next selection in lexicographic order as permutations are exhausted
    ...
    [3,2,1]   // reached last permutation of current selection
    

    代码(基于 0 的索引,所以从 0-k-1 初始化开始):

    bool next_combination_with_order(vector<int>& a, int n, bool order_matters=true) {
        int k = (int)a.size();
        if(order_matters && std::next_permutation(a.begin(), a.end()))return True; // check if next permutation exists otherwise move forward and get next unique combination
        // if `a` was already in descending order, 
        // next_permutation returned false and changed the array to sorted order.
        // now find next combination if possible
        for (int i = k - 1; i >= 0; i--) {
            if (a[i] < n - k + i + 1) {
                a[i]++;
                for (int j = i + 1; j < k; j++)
                    a[j] = a[j - 1] + 1;
                return true;
            }
        }
        return false;
    }
    

    参考资料:

    下一个排列:

    https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order

    std::next_permutation Implementation Explanation

    下一个无顺序组合:

    https://cp-algorithms.com/combinatorics/generating_combinations.html

    【讨论】:

    • 没有必要构建所有排列,因为只存在 N!/(N-K)!有效的。
    • “next_permutation 函数给出下一个字典顺序唯一的排列”。新创建的数组A中有N-k重复值0。所以会有 N!/(N-k)!独特的排列。
    • 很好的答案!谢谢!
    • 欢迎,很高兴它有帮助!
    • 如果顺序无关紧要怎么办?如何获得 N!/(k!(N-k)!) 个唯一组合?
    猜你喜欢
    • 2013-11-18
    • 2023-03-12
    • 1970-01-01
    • 2013-06-24
    • 2016-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-15
    相关资源
    最近更新 更多