是否有可能在 O(1) 中获得 m 个字符长度组合的第 k 个元素?

Posted

技术标签:

【中文标题】是否有可能在 O(1) 中获得 m 个字符长度组合的第 k 个元素?【英文标题】:Is it possible to get k-th element of m-character-length combination in O(1)? 【发布时间】:2011-08-26 00:54:39 【问题描述】:

你知道在 O(1) 中获得 m 元素组合的第 k 个元素的方法吗?预期的解决方案应该适用于任何大小的输入数据和任何 m 值。

让我通过例子来解释这个问题(python代码):

>>> import itertools
>>> data = ['a', 'b', 'c', 'd']
>>> k = 2
>>> m = 3
>>> result = [''.join(el) for el in itertools.combinations(data, m)]
>>> print result
['abc', 'abd', 'acd', 'bcd']
>>> print result[k-1]
abd

对于给定的 data,m 元素组合的第 k 个(本例中为第 2 个)元素是 abd。是否可以在不创建整个组合列表的情况下获得该值 (abd)?

我问是因为我有大约 1,000,000 个字符的数据,并且不可能创建完整的 m 字符长度组合列表来获取第 k 个元素。

解决方案可以是伪代码,也可以是描述此问题的页面链接(很遗憾,我没有找到)。

谢谢!

【问题讨论】:

为此,您需要明确定义的组合顺序。 【参考方案1】:

http://en.wikipedia.org/wiki/Permutation#Numbering_permutations

基本上,在阶乘数字系统中表示索引,并将其数字用作原始序列中的选择(无需替换)。

【讨论】:

secure.wikimedia.org/wikipedia/en/wiki/… 这不是更有帮助吗? 是的。我是一个白痴。我把它读成排列,而不是组合。它们之间可能存在一个简单的映射,例如从一组 N 个唯一元素中提取的 k 个元素的第 j 个组合与 N 个元素的 j(k!)((N-k!)th 排列的前 k 个元素相同。但也许不是。【参考方案2】:

不一定是 O(1),但下面的应该很快:

取原来的组合算法:

def combinations(elems, m):
    #The k-th element depends on what order you use for
    #the combinations. Assuming it looks something like this...
    if m == 0:
        return [[]]
    else:
        combs = []
        for e in elems:
            combs += combinations(remove(e,elems), m-1)

对于n 初始元素和m 组合长度,我们有n!/(n-m)!m! 总组合。我们可以利用这个事实直接跳到我们想要的组合:

def kth_comb(elems, m, k):
    #High level pseudo code
    #Untested and probably full of errors
    if m == 0:
        return []
    else:
        combs_per_set = ncombs(len(elems) - 1, m-1)
        i = k / combs_per_set
        k = k % combs_per_set
        x = elems[i]
        return x + kth_comb(remove(x,elems), m-1, k)

【讨论】:

【参考方案3】:

首先计算r = !n/(!m*!(n-m))与n的元素数量

那么 floor(r/k) 是结果中第一个元素的索引,

删除它(将所有内容向左移动)

做 m--, n-- 和 k = r%k

并重复直到 m 为 0(提示 k 为 0 时只需将以下字符复制到结果中)

【讨论】:

【参考方案4】:

我编写了一个类来处理处理二项式系数的常用函数,这是您的问题似乎属于的问题类型。它执行以下任务:

    以适合任何 N 选择 K 的格式将所有 K 索引输出到文件。 K-indexes 可以替换为更具描述性的字符串或字母。这种方法使得解决这类问题变得非常简单。

    将 K 索引转换为已排序二项式系数表中条目的正确索引。这种技术比依赖迭代的旧已发布技术快得多。它通过使用帕斯卡三角形固有的数学属性来做到这一点。我的论文谈到了这一点。我相信我是第一个发现并发表这种技术的人,但我可能是错的。

    将已排序二项式系数表中的索引转换为相应的 K 索引。我相信它也比其他已发布的技术更快。

    使用Mark Dominus 方法计算二项式系数,该方法不太可能溢出并且适用于较大的数字。

    该类是用 .NET C# 编写的,并提供了一种通过使用通用列表来管理与问题相关的对象(如果有)的方法。此类的构造函数采用一个名为 InitTable 的 bool 值,当它为 true 时,将创建一个通用列表来保存要管理的对象。如果此值为 false,则不会创建表。无需创建表即可执行上述 4 种方法。提供访问器方法来访问表。

    有一个关联的测试类显示如何使用该类及其方法。它已经过 2 个案例的广泛测试,没有已知的错误。

要了解该课程并下载代码,请参阅Tablizing The Binomial Coeffieicent。

将此类转换为 Java、Python 或 C++ 应该不难。

【讨论】:

以上是关于是否有可能在 O(1) 中获得 m 个字符长度组合的第 k 个元素?的主要内容,如果未能解决你的问题,请参考以下文章

哈希+组合数学+思维

字典排序O(m)

python每天1道面试题--字符串组合

KMP算法

Matlab:在for循环中排除零值矩阵单元的if条件

如何获得二维数组可能的组合