【问题标题】:Indexing subsets of size k [duplicate]索引大小为 k 的子集
【发布时间】:2013-11-30 02:52:18
【问题描述】:

有 n 个选择 k 个大小为 k 的 {1,2,...,n} 的子集。这些可以通过对元素进行排序并使用字典顺序来自然排序。

有没有一种快速的方法来确定给定子集的索引,即它在大小为 k 的所有子集的排序列表中的索引?一种方法是通过枚举所有大小为 k 的子集来创建从子集到索引的字典,但这需要 n 选择 k 个空间和时间。对于我的应用,n 和 k 太大了,但我只需要确定相对较少的子集的索引。

我正在使用 Python 进行编码,但我对通用算法比对任何特定实现更感兴趣。当然,如果在 Python 中有一种特别快速的方法可以做到这一点,那就太好了。

动机:大小为 k 的 {1,2,...,n} 的子集双射对应于维数为 n 的向量空间的第 k 个外幂的基向量。我正在向量空间的外部代数中执行计算,并尝试将结果向量列表转换为稀疏矩阵以进行线性代数,为此我需要按整数而不是列表来索引向量。

【问题讨论】:

  • 它看起来确实像复制品。如前所述,阶乘基础答案不太适合问题;根据 n 和 k 的大小,这可能是也可能不是问题。一个简单的快速估计似乎表明接受的答案执行了不必要的计算量,O(n) 调用了n choose k 函数而不是O(k)。这实际上可能会或可能不会导致放缓;我没有考虑到 n choose k 函数的运行时对其输入的依赖性。无论如何,看到现有的工作是很好的。
  • @user2357112 该链接恰当地回答了我的问题:我必须执行的线性代数计算在阶乘之前变得不可行。

标签: python algorithm indexing subset


【解决方案1】:

s 是一个排序列表,表示给定的 1..n 子集。

(n-s[0]) choose k 子集的最低元素大于s[0]。在以s[0] 开头的子集中,(n-s[1]) choose (k-1) 子集的第二个元素大于s[1],依此类推。我还没有做出证明,但以下功能应该可以工作:

def choose(n, k):
    ...

def index_of(sorted_subset, n):
    k = len(sorted_subset)
    subsets_after_the_input = 0
    for i, elem in enumerate(sorted_subset):
        subsets_after_the_input += choose(n-elem, k-i)
    return choose(n, k) - subsets_after_the_input - 1

【讨论】:

  • 是的,我认为这比我的答案要好 - 计算要简单得多。蒂姆·彼得斯提出的重复问题的各种答案也令人印象深刻。
【解决方案2】:

我认为您可以通过递归缩小范围来做到这一点,对吧?您知道以给定整数开头的所有子集都是相邻的,并且对于给定的第一个元素 d 将有 (n - d) 个选择 (k-1) 个。您可以在虚拟子集列表中尽可能向前跳过,直到您处于从目标排序子集的第一个元素开始的子集范围内,然后递归以精确缩小范围。

EG,假设 n=20,k=6。如果您的目标子集是 {5, 8, 12, 14, 19},则以 1-4 开头的子集都不是有效选择。您知道以 5 开头的索引第一个子集将是 ((19 选择 5) + (18 选择 5) + (17 选择 5) + (16 选择 5))。将该索引称为 i0。现在您有(15 个选择 5)子集,所有子集都以 5 开头要索引,而以 5、1-7... 开头的子集都不是有趣的。 (14 选 4) 以 1 开头,(13 选 4) 以 2 开头,依此类推。所以第一组的索引以 5 开头,8 将是 i0 + (14 选 4) + (13 选 4) + (12选4)+(11选4)+(10选4)+(9选4)+(8选4)。等等。

写出算法有点痛苦,但我认为它应该可以很好地与跟踪繁琐细节的计算机一起使用。

【讨论】:

  • 你的数学是错误的。绝对没有以给定整数开头的(n-1) choose (k-1) 子集,除非该整数为 1,例如。
  • @user2357112 - 是的,刚刚发现。我认为算法仍然合理,但我需要修复计算。
  • 确实有n-d个选择k-1个以d开头的大小为k的子集,所以第一个以d开头的子集的索引是n-1个选择k-1 + ... + n-d +1 选择 k-1。谢谢,这很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-06
  • 2022-01-24
  • 2017-09-09
相关资源
最近更新 更多