【问题标题】:How to find possible set of k Elements from array?如何从数组中找到可能的 k 个元素集?
【发布时间】:2015-12-10 13:13:17
【问题描述】:

我有一个数组{1,2,3,4,5,6,7,8,9,10},我必须从array 中找到k 个元素的所有组合,并且k 将是动态的。因此,对于下面的 4 个元素,代码就足够了,但我必须采用这种动态方式,不固定将使用多少个 for 循环,所以请为此提出一些解决方案。

 for (i = 0; i < len - 3; i++)    
 {   
    for (j = i + 1; j < len - 2; j++)           
    {
       for (y = j + 1; y < len - 1; y++)              
       {                
          for (k = y + 1; k < len; k++)                    
          Console.WriteLine("{0},{1},{2},{3}", s[i], s[j],s[y], s[k]);             
       }                
    }
 }

【问题讨论】:

  • 我不知道您是否阅读了我上次发布此问题时提到的博客,但它确实包含可以为您执行此操作的代码。 ericlippert.com/2014/10/13/producing-combinations-part-one
  • 我不想使用 linq。
  • 那篇文章没有“使用 Linq”。它确实使用了扩展方法,但如果您不喜欢,您仍然可以从该代码中学习。
  • 那么您需要准确定义“基本 c#”的含义。您是否仅限于 .net 2.0?除了最后的扩展方法,如果你愿意,它可以用作常规的静态方法,我很确定其他所有东西都可以在 2.0 中编译。
  • 这似乎是一个关于递归的作业,很遗憾你不得不在这里要求解决你的硬件

标签: c# .net recursion


【解决方案1】:

您只需将i, j, y, ... 替换为数组并像这样手动展开for 循环

static void PrintCombinations(int[] input, int k)
{
    var indices = new int[k];
    for (int pos = 0, index = 0; ; index++)
    {
        if (index <= input.Length - k + pos)
        {
            indices[pos++] = index;
            if (pos < k) continue;
            // Consume the combination
            for (int i = 0; i < k; i++)
            {
                if (i > 0) Console.Write(",");
                Console.Write(input[indices[i]]);
            }
            Console.WriteLine();
            pos--;
        }
        else
        {
            if (pos == 0) break;
            index = indices[--pos];
        }
    }
}

【讨论】:

    【解决方案2】:

    您可以使用此方法生成大小 l 的组合

    public static List<List<T>> GenerateCombinations<T>(List<T> items, int l)
    {
        if (l == 0)
            return new List<List<T>> { new List<T>() };
    
        var allCombs = new List<List<T>>();
        for (int i = 0; i < items.Count(); i++)
        {
            var listWithRemovedElement = new List<T>(items);
            listWithRemovedElement.RemoveRange(0, i + 1);
    
            foreach (var combination in GenerateCombinations(listWithRemovedElement, l - 1))
            {
                var comb = new List<T>(listWithRemovedElement.Count + 1);
                comb.Add(items[i]);
                comb.AddRange(combination);
                allCombs.Add(comb);
            }
        }
        return allCombs;
    }
    

    您可以使用此方法生成大小为 l 的排列

    public static List<List<T>> GeneratePermutations<T>(List<T> items, int l)
    {
        if (l == 0)
            return new List<List<T>> { new List<T>() };
    
        var allCombs = new List<List<T>>();
        for (int i = 0; i < items.Count(); i++)
        {
            var listWithRemovedElement = new List<T>(items);
            listWithRemovedElement.RemoveAt(i);
    
            foreach (var combination in GeneratePermutations(listWithRemovedElement, l - 1))
            {
                var comb = new List<T>(listWithRemovedElement.Count + 1);
                comb.Add(items[i]);
                comb.AddRange(combination);
                allCombs.Add(comb);
            }
        }
        return allCombs;
    }
    

    { 1, 2, 3 } 大小为 2 的排列

    var result = GeneratePermutations(new List<int>() { 1, 2, 3 }, 2);
    foreach (var perm in result)
        Console.WriteLine(string.Join(",", perm));
    
    1,2
    1,3
    2,1
    2,3
    3,1
    3,2
    

    { 1, 2, 3 } 大小为 2 的组合

    var result = GenerateCombinations(new List<int>() { 1, 2, 3 }, 2);
    foreach (var comb in result)
        Console.WriteLine(string.Join(",", comb));
    
    1,2
    1,3
    2,3
    

    【讨论】:

    • 感谢您的努力
    【解决方案3】:

    这不是我在“现实生活”中的做法,但由于这似乎是一个简单的家庭作业式问题,旨在让您使用递归并简单地写出组合,这个是一个相当简单的解决方案:

    class Program
    {
        public static void Main()
        {
            int[] test = { 1, 2, 3, 4, 5 };
            int k = 4;
    
            WriteCombinations(test, k);
            Console.ReadLine();
        }
    
        static void WriteCombinations(int[] array, int k, int startPos = 0, string prefix = "")
        {
            for (int i = startPos; i < array.Length - k + 1; i++)
            {
                if (k == 1)
                {
                    Console.WriteLine("{0}, {1}", prefix, array[i]);
                }
                else
                {
                    string newPrefix = array[i].ToString();
                    if (prefix != "")
                    {
                        newPrefix = string.Format("{0}, {1}", prefix, newPrefix);
                    }
                    WriteCombinations(array, k - 1, i + 1, newPrefix);
                }
            }
        }
    }
    

    如果可选参数不够“基本”,那么您可以去掉默认值并在第一次调用时传入0"",或者您可以创建另一个“包装器”方法,它需要更少参数,然后使用默认值调用第一个方法。

    【讨论】:

      猜你喜欢
      • 2014-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-04
      相关资源
      最近更新 更多