【问题标题】:Print all Possible Combinations out a List with Max Values将所有可能的组合打印出具有最大值的列表
【发布时间】:2022-01-11 05:29:52
【问题描述】:

我尝试在 C# 中实现的算法有问题(我猜该语言无关紧要)。

假设我有一个可以是任意长度的列表..例如:

var maxNumbers = new List<int>{5,3,2}();

列表中的数字代表每个条目的最大值。例如,第一个条目表示它可以是 1 到 5 之间的任意数字(包括 5)。

现在,我想打印列表中每个条目的每个可能值的所有组合。

解释一下:

  • 列表中的第一个数字是 5,因此可能的值是 1,2,3,4,5
  • 列表中的第二个数字是 3,因此可能的值 是 1,2,3
  • 列表中的最后一个数字是 2,所以可能的值 是 1,2

我的算法应该打印如下内容:

1-1-1

1-1-2

1-2-1

1-2-2

1-3-1

1-3-2

1-2-1

等等

我尝试使用递归来实现这一点,但无法实现。这是我的代码:

    void Iterate(List<int> numbers)
{
    if (numbers.Count == 0)
    {
        Console.WriteLine("");
        return;
    }
    int number = numbers[0];
    for (int i = 1; i <= number; i++)
    {
        Console.WriteLine($"{i} ");
        Iterate(numbers.Where((v, index) => index != 0).ToList());
    }

}

谁能提供见解?

【问题讨论】:

  • 要求非常模糊,我会提供一个包含整个所需输出的最小示例,以便人们可以得到它。例如为什么链中总是有 3 个整数...
  • 我认为最后一个例子是一个错字。链中有 3 个,因为输入有 3 个最大值。如果 maxNumber 中有 5 个最大值,则输出将有 5 个,例如 1-1-1-1-1、1-1-1-1-2..
  • @CaiusJard 一个假设……万恶之源 =)

标签: c# algorithm iteration combinations


【解决方案1】:

非递归方法;

我们使用 Select(Enumerable.Range) 将您的最大值列表转换为代表所有数字的整数列表。

然后我们反复使用 SelectMany 将另一个级别添加到列表中。 SelectMany 期望被提供一个可枚举的。在第一个实例中,组合中只有一个项目,它与整数中第一个条目的 5 个项目交叉,因此 SelectMany 产生 5 个项目。 第二轮 SelectMany 有效地认为它正在将“5 个 3 个项目的列表”扩展为“15 个项目的列表”。第三轮 SelectMany 认为它正在将“15 个 2 项列表”扩展为“30 项列表”...

 public static string[] Combine(IEnumerable<int> maxes)
 {
     var ints = maxes.Select(max => Enumerable.Range(1, max));
     IEnumerable<string> combos = new[] { "" };

     foreach (var i in ints)
     {
         combos = combos.SelectMany(r => i.Select(x => r + (r == "" ? "" : "-") + x));
     }

     return combos.ToArray();
 }

【讨论】:

  • 非常有趣和简化的方法。谢谢。
【解决方案2】:

这个答案修复了您的代码,对我来说,关键问题是该解决方案没有携带任何记忆到目前为止它已经达到了输出,因此没有任何方法可以迭代重复前面的循环输出

这里是固定代码:

static void Iterate(List<int> numbers, string sofar)
{
    if (numbers.Count == 0)
    {
        Console.WriteLine(sofar);
        return; 
    }
    
    for (int i = 1; i <= numbers[0]; i++)
    {
        Iterate(numbers.Skip(1).ToList(), sofar + i + " ");
    }
}

您在问题中的代码有点错字,因为它在 for 循环中执行了 WriteLine,这确实弄乱了输出。删除它只是写你得到:

1 1 1 
2 
2 1 
2 
3 1 
2 
2 1 1 
2 
2 1 
2 
3 1 
2 
3 1 1 
2 
2 1 
2 
3 1 
2 
4 1 1 
2 
2 1 
2 
3 1 
2 
5 1 1 
2 
2 1 
2 
3 1 
2

如果我添加一些空格来改变对齐方式:

1 1 1 
    2    --> it's 1 1 2
  2 1    --> it's 1 2 1
    2    --> it's 1 2 2 etc
  3 1 
    2 
2 1 1 
    2 
  2 1 
    2 
  3 1 
    2 
3 1 1 
    2 
  2 1 
    2 
  3 1 
    2 
...

您可以看到它几乎就在那里,因为它正在打印每次都会更改的数字,它只是失去了对于未更改的数字要打印的内容的任何记忆。修改后的代码传递了“我们目前生成的字符串”,并将打印它的责任交给了if。每次循环调用 Iterate 时,它​​都会传递到目前为止构建的字符串,因此它会记住它到达的位置

【讨论】:

  • 这很有意义。非常感谢
  • 没问题!关于如何使用堆栈溢出的快速教程:当有人写出您认为有用或有帮助的答案时,请单击数字上方的向上箭头?。当有人写下您最终用来解决问题的答案时,请单击灰色复选 ☑️ 将其变为绿色 ✅。您可以在许多答案上单击?,包括您检查的答案,但只能检查一个答案✅ - 当您这样做时,它会更改仪表板上问题的外观,因此人们知道您不是仍在寻找答案
猜你喜欢
  • 2018-09-25
  • 1970-01-01
  • 2011-12-09
  • 2017-08-17
  • 1970-01-01
  • 2016-09-02
  • 1970-01-01
相关资源
最近更新 更多