如何获得一组可复制元素的所有唯一n长组合?

时间:2013-06-23 04:18:52

标签: c# algorithm combinatorics

我找到了许多解决方案,它们在所有可能的顺序中组合了一个集合元素,但它们在每个结果中只使用一次元素,而我需要将它们视为可重用的。

例如,如果输入元素为{“a”,“b”,“c”}且数字为2,则输出为{“a”,“a”},{“a”,“b” },{“a”,“c”},{“b”,“a”},{“b”,“b”},{“b”,“c”},{“c”,“a” },{“c”,“b”},{“a”,“c”}。

5 个答案:

答案 0 :(得分:1)

假设你有N个输入元素,你想要一个K-long组合。

您需要做的就是计算基数N,当然还要计算所有带有K位数的数字。

所以,假设N = {n0,n1,... nN}

你从数字[n0 n0 ... n0]开始,一直计数到[nN nN ... nN]

如果您希望了解如何计算其他基数,请获取here

您计算的每个数字都映射到您需要的K长组合之一。

我认为一个例子可以帮助

我会用你的价值观。 N = {a,b,c} 所以我们想要算在3号基数。 由于我们需要2长组合,我们只关心2位数字。 最小的2位数基数3是00,所以我们从那里开始。通过计算基数3,我们得到:

00
01
02
10
11
12
20
21
22

好的,现在将这些数字转换为组合。

请记住,我们的设置为{a,b,c}

所以每当我们看到0时,它就意味着1.无论我们在哪里看到1,它都意味着2,我相信你能猜出2意味着什么:)

00              aa
01              ab
02              ac
10   0 => a     ba
11   1 => b     bb
12   2 => c     bc
20              ca
21              cb
22              cc

答案 1 :(得分:1)

您可以使用depth first search

class Program
{
    private static string[] letters = {"a", "b", "c"};
    private static void dfs(string accum, int depth)
    {
        if (depth == 0)
        {
            System.Console.WriteLine(accum);
            return;
        }
        foreach (string c in letters)
            dfs(accum + c, depth - 1);
    }
    public static void Main()
    {
        int depth = 2; //Number of letters in each result
        dfs("", depth);
        System.Console.ReadLine();
    }
}


输出:

aa
ab
ac
ba
bb
bc
ca
cb
cc

答案 2 :(得分:1)

Eric Lippert介绍了一种通用方法,可以从任意数量的序列which he blogs about here生成笛卡尔积。

他写了一个如下所示的扩展方法:

public static class Combinations
{
    public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
    {
        IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
        return sequences.Aggregate(
            emptyProduct,
            (accumulator, sequence) =>
            from accseq in accumulator
            from item in sequence
            select accseq.Concat<T>(new[] { item }));
    }
}

鉴于扩展方法,原始问题的解决方案可以这样做:

var items = new[] { "a", "b", "c" };

int numInEachSelection = 2;

var combs = Enumerable.Repeat(items, numInEachSelection).CartesianProduct();

foreach (var comb in combs)
    Console.WriteLine(string.Join(", ", comb));

请注意combsIEnumerable<IEnumerable<string>> - 它是一系列枚举,每个都是代表一个组合的序列。

如果您不需要这样的通用方法,并且您乐意将每个组合放在一个单独的对象中,该对象具有两个组合项目Item1Item2的属性,那么最简单方式是这样的:

var items = new[] { "a", "b", "c" };

var combs = from Item1 in items from Item2 in items select new {Item1, Item2};

foreach (var comb in combs)
    Console.WriteLine(comb);

答案 3 :(得分:0)

简单 - 你算一算。如果您有3个元素,如您的示例所示,并且想要所有双元素组合,则只需从0到8(3 ^ 2 - 1)计数,并将结果视为基数为3的数字,并将元素作为数字

如果您有15个元素并且需要8个元素组合,则从0到15 ^ 8-1计数并将结果视为基数为15的数字。

答案 4 :(得分:0)

你要求的是排列而不是组合。通过遍历n个元素的k,可以找到唯一的组合。如果你想要n个n个唯一元素,那么答案是1