运行时嵌套循环的数量

时间:2009-11-23 16:26:34

标签: c# runtime nested-loops

我试图输出从1到最大的所有可能的唯一整数组合,用于设定的整数数。所以对于3个整数,最多4个,我会得到:

123 124 134 234

我使用嵌套for循环执行此操作但我想允许用户在运行时输入整数数。现在我有

if(numInts >6);
for(int x = 1; x < max; x++);
if(numInts >5);
for(int y = 1; y < max; y++);
...

有没有办法清理它,所以我不必写出每个可能的循环整数。

PS:我知道上面的代码不会输出请求的输出。这是一个程序竞赛,所以我不是要求代码解决方案只是让这成为可能的想法。

6 个答案:

答案 0 :(得分:3)

一个字: Recursion

答案 1 :(得分:1)

使用递归,numInts成为调用树的深度。

答案 2 :(得分:1)

查看维基百科上的组合。这些是你想要产生的。

编辑:起初,我认为OP意味着permeations。以下代码不适用于组合,但我会将其保留在此处,以防有人想要调整它以使其工作。

正如其他人所说,这是递归擅长的问题。让我们调用你的函数pick(num, list)。这是一些伪代码。

List pick(Int num, List list)
{
  if (num == 1) // base case
  {
    return list
  }
  else // recurring case
  {
    var results = []
    foreach (item in list)
    {
      alteredList = list.copy().remove(item)
      results.add([item] + pick(num - 1, alteredList))
    }
    return results
  }
}

关于上述代码的一些注释。请注意这两种情况。递归几乎总是遵循基本案例/重复案例格式。实际递归发生在行results.add([item] + pick(num - 1, alteredList))中,关键点是您传递num-1。这意味着,在每次调用pick时,num会变得越来越小,直到达到1(当它达到1时,它已完成)。

名为alteredList的变量创建为列表的COPY,并删除了当前项。大多数语言都有removed方法,但它改变了原始列表(这不是你想要的!)当变量是不可变的时(当它们不被改变时),递归效果最好。

最后,我想澄清一下[item] + pick(num - 1, alteredList)行。我只是意味着创建一个新列表,其第一个元素是item,其余元素是调用pick(num - 1, alteredList)返回的列表。在Lisp中,将一个元素添加到列表前面的操作称为cons。这种cons操作在函数式语言中非常强大,其中递归被大量使用,但是用命令式语言表达是很尴尬的,例如Java / C#。

答案 3 :(得分:1)

查看您对原始帖子的评论,您需要一个迭代解决方案。当您拥有支持尾调用优化的语言时,递归解决方案将与迭代解决方案一样快。但是,如果您正在使用Java / C#,那么这是不可用的,所以这是另一种查看问题的方法。

您正在生成组合。组合只是具有一定数量元素的子集。具有小集合的子集可以用位掩码表示。

如果我有集合[1, 2, 3, 4]并且我想描述子集[1, 3, 4],我可以通过遍历每个元素并询问“是或否:子集中的这个元素?”来实现。{因此,对于[1, 3, 4],结果为[True, False, True, True]。如果我使用的是小于32(或64)字节的集合,我可以将其编码为整数:1011b = 11.这在内存中非常紧凑,计算机往往具有非常快的位图运算符。

那么就这些二进制数而言,那么组合是什么?如果我想要所有具有N个成员的子集,我可以将其翻译为“我想要设置N位的所有数字”。

像往常一样采取[1, 2, 3, 4]。我们想要所有具有3个元素的子集。有多少个4位数字,正好设置了3位?答案:1110b,1101b,1011b和0111b。如果我们将这些整数转换为子集,我们会得到您的解决方案:[1, 2, 3][1, 2, 4][1, 3, 4][2, 3, 4]

你可以开始考虑比特。从N位设置的最低编号开始。这对应于一个解决方案。然后,您开始一对一地翻转位。以系统的方式使每次迭代总是产生下一个最高的数字。

答案 4 :(得分:0)

internal class Program {
    private static void Main(string[] args) {
        foreach (var combination in AllCombinations(new[] { 1, 2, 3 })) {
            Console.WriteLine(string.Join("", combination.Select(item => item.ToString()).ToArray()));
        }
    }

    private static IEnumerable<IEnumerable<T>> AllCombinations<T>(IEnumerable<T> elements) {
        if (elements.Count() == 1) yield return new[] { elements.First() };
        else {
            foreach (var element in elements) {
                foreach (var combination in AllCombinations(elements.Except(new[] { element }))) {
                    yield return (new[] { element }).Concat<T>(combination);
                }
            }
        }
    }
}

答案 5 :(得分:0)

你需要嵌套for循环的问题通常是为递归而喊。

想象一下像

这样的树
<root>
    <1>
       <1>
          <1>
          <2>
          <3>
          <4>
       <2>
          <1>
          <2>
          <3>
          <4>
    ...

然后遍历树(递归)并收集'有效路径'