【问题标题】:How to get all the unique n-long combinations of a set of duplicatable elements?如何获得一组可复制元素的所有唯一 n 长组合?
【发布时间】:2013-06-23 04:18:51
【问题描述】:

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

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

【问题讨论】:

  • 这称为“替换组合”,在数学上等价于给定集合与集合 {1,2,3...n} 的笛卡尔积。您通常不会在库中找到它,因为它被认为太简单以至于不需要它。正如您所指出的那样,无需替换的组合在库中很常见,因为它们更棘手。

标签: c# algorithm combinatorics


【解决方案1】:

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

您所需要做的就是以 N 为底数,当然范围是所有具有 K 位的数字。

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

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

如果您在了解如何计算另一个基地方面需要帮助,请联系here

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

我认为一个例子会有所帮助

我会使用你的价值观。 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

【讨论】:

    【解决方案2】:

    您可以使用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
    

    【讨论】:

      【解决方案3】:

      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&lt;IEnumerable&lt;string&gt;&gt; - 它是一个可枚举序列,每个可枚举序列代表一个组合。

      如果您不需要这样的通用方法,并且您很乐意将每个组合放在一个单独的对象中,并为这两个组合项提供名为 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);
      

      【讨论】:

        【解决方案4】:

        简单——你数数。如果您有 3 个元素,如您的示例所示,并且想要所有两个元素的组合,您只需从 0 数到 8 (3^2 - 1),并将结果视为以 3 为底的数字,元素为数字.

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

        【讨论】:

          【解决方案5】:

          您要求的是排列而不是组合。可以通过对 n 个元素中的 k 个进行树遍历来找到唯一的组合。如果你希望 n 个元素中的 n 个是唯一的,答案是 1

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-06-05
            • 2020-12-20
            • 1970-01-01
            • 2012-04-09
            • 2022-01-18
            • 2018-05-15
            • 2020-10-11
            • 2013-02-02
            相关资源
            最近更新 更多