我试图输出从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:我知道上面的代码不会输出请求的输出。这是一个程序竞赛,所以我不是要求代码解决方案只是让这成为可能的想法。
答案 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>
...
然后遍历树(递归)并收集'有效路径'