【发布时间】:2021-01-10 05:18:48
【问题描述】:
我正在寻找一种迭代算法来获得从一组 N 个元素中提取的 K 个元素的所有排列,没有重复(即没有替换),并且顺序很重要。 我知道排列的数量必须是 N!/(N-K)!。 你有什么想法吗? 谢谢。
伊万
【问题讨论】:
标签: algorithm iteration permutation
我正在寻找一种迭代算法来获得从一组 N 个元素中提取的 K 个元素的所有排列,没有重复(即没有替换),并且顺序很重要。 我知道排列的数量必须是 N!/(N-K)!。 你有什么想法吗? 谢谢。
伊万
【问题讨论】:
标签: algorithm iteration permutation
方法一:
更简单的想法:
由于订单很重要,我们将尝试使用next_permutation algorithm。 next_permutation 函数给出下一个字典顺序唯一的排列。
算法:
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)
算法:
A 中,它将存储原始数组中所选元素的索引。我们将其标记为第一个选择。如果排列用尽,则按词典顺序获取下一个选择的想法:
我们考虑我们当前的组合,并找到最右边的元素 尚未达到其可能的最高值。一旦发现这个 元素,我们将其增加 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
【讨论】:
A中有N-k重复值0。所以会有 N!/(N-k)!独特的排列。