【发布时间】:2013-03-03 13:07:06
【问题描述】:
我正在尝试创建一个生成器(支持执行下一个操作的迭代器,可能在 python 中使用 yield),它提供来自 {1,2,...n} 的 r 元素的所有组合(n 和 r 是参数),例如在选定的 r 个元素中,没有两个是连续的。
例如,对于 r = 2 和 n= 4
生成的组合是{1,3}, {1,4}, {2, 4}。
我可以生成所有组合(作为迭代器)并过滤那些不满足条件的组合,但我们将做不必要的工作。
是否有某种生成算法使得next 为 O(1)(如果不可能,则为 O(r) 或 O(n))。
返回集合的顺序不相关(希望允许 O(1) 算法)。
注意:我已将其标记为 python,但与语言无关的算法也会有所帮助。
更新:
我找到了一种将其映射到生成纯组合的方法!网络搜索显示 O(1) 是可能的组合(虽然看起来很复杂)。
这是映射。
假设我们有 x_1, x_2, ... , x_r 和 x_1 + 1 < x_2, x_2 + 1 < x_3, ... 的组合
我们映射到y_1, y_2, ..., y_r如下
y_1 = x_1
y_2 = x_2 - 1
y_3 = x_3 - 2
...
y_r = x_r - (r-1)
这样我们就有了y_1 < y_2 < y_3 ... 没有非连续约束!
这基本上相当于从 n-r+1 中选择 r 个元素。因此,我需要做的就是运行 (n-r+1 choose r) 的生成。
就我们的目的而言,在事物生成之后使用映射就足够了。
选择svkcr答案的原因
所有很好的答案,但我选择了 svkcr 的答案。
以下是一些原因
它实际上是无状态的(或者更准确地说是“马尔可夫”)。下一个排列可以从前一个排列生成。它在某种程度上几乎是最优的:O(r) 空间和时间。
这是可以预见的。我们确切地知道生成组合的顺序(字典顺序)。
这两个属性使生成的并行化变得容易(在可预测的点拆分和委托),并引入了容错(如果 CPU/机器出现故障,可以从最后生成的组合中挑选出来)!
抱歉,前面没有提到并行化,因为我在写这个问题时没有想到它,后来才知道。
【问题讨论】:
-
生成和过滤不会是 O(n) 吗?或者,实际上,O(r)?从 1 到 r 的每个槽只有一个非法值,因此最多可以跳过 (r-1) 个组合。
-
PS,“生成所有组合(作为迭代器)”是与
itertools的单行。 -
@abarnert:可能是 Omega(nr)(或更糟),不是吗?感谢您提供有关 itertools 的提示。
-
怎么会是nr?我们中的一个人需要仔细考虑这一点。但请记住,您可以假设组合按排序顺序到达。
-
@abarnert:底层生成器可能是 Omega(n),所以如果你跳过 r 次调用,你就有了 Omega(nr)。不过,您是对的,需要(由我)给予更多思考。
标签: python algorithm combinations