algorithm – 检索子集的词典索引

我有一个列表,其中包含按字典顺序排序的集合{1,2,…,n}中所有大小为k的子集,例如集合{1,2,3,4}中所有大小为2的子集{ 1,2},{1,3},{1,4},{2,3},{2,4},{3,4}.其中{1,2}的索引为0,{1,3}为1,依此类推.

现在,我需要编写一个接收子集的算法(假设子集是有序的),并在列表中返回其索引.

我写了以下算法:

int GetSubsetIndex(List<int> subset, int N)
{
    int Skip = 0;
    int Last = 0;
    int Depth = 1;
    int K = subset.Count;

    while (Depth <= K)
    {
        for (int i = Last + 1; i < subset[Depth - 1]; i++)
        {
            Skip += BinomialCoefficient(N - i, K - Depth);
        }

        Last = subset[Depth - 1];
        Depth++;
    }

    return Skip;
}

该算法使用子集的词典顺序的特殊结构,这里是解释:

假设我们有一组大小为6(N = 6)和长度为3的子集(K = 3),那么我们有6个选择3个子集.现在,以1开头的子集数量是5选择2,以2开头的子集数量是4选择2,依此类推……

如果子集中的第一个数字是X,我们可以跳过(N-1选择K-1)(N-2选择K-1)…(N-X选择K-1)子集.
如果X是第一个数,则子集中的第二个数Y至少为X 1.现在我们可以跳过(N- [X 1]选择K-2)(N- [X 2]选择K-2). (纽约选择K-2)等等.

在算法的代码中,Skip表示我们跳过的子集的数量,last表示我们在子集中考虑的最后一个数字(初始化为0,因为集合从1开始),深度是我们的子集有多深,K是所有子集的长度.

如果二项式系数计算为O(1)(如果是预处理的)或O(N * k)(如果不是),则该算法的问题是以O(N)时间运行,在实践中可以非常快速地计算一些子集.我试图找到一种方法,以缩短时间限制获得此索引.

只要不使用超过O(N chooke K)内存(即子集数量),就可以进行任何预处理.

最佳答案 你想要的答案是组合数字系统.见
http://en.wikipedia.org/wiki/Combinatorial_number_system

您可以找到查找大小为k的第n个子集的指令,或者对于大小为k的子集,查找其索引.

点赞