And*_*iak 4 c# algorithm statistics
我尝试解决下一个练习:
输入:带有count >= 1;一些正整数的整数列表k
输出: 这个整数的所有可能的元组,长度为k;
例如
输入: {1, 2}; k = 4
输出:
{
{1, 1, 1, 1},
{1, 1, 1, 2},
{1, 1, 2, 1},
{1, 1, 2, 2},
{1, 2, 1, 1},
{1, 2, 1, 2},
{1, 2, 2, 1},
{1, 2, 2, 2},
{2, 1, 1, 1},
{2, 1, 1, 2},
{2, 1, 2, 1},
{2, 1, 2, 2},
{2, 2, 1, 1},
{2, 2, 1, 2},
{2, 2, 2, 1},
{2, 2, 2, 2}
}
Run Code Online (Sandbox Code Playgroud)
我试图创建一个包含输入列表副本的数组,然后使用:k Combinations
public static IEnumerable<IEnumerable<T>> Combinations<T>(
this IEnumerable<T> elements,
int k)
{
return k == 0
? new[] { new T[0] }
: elements.SelectMany((e, i) => elements
.Skip(i + 1)
.Combinations(k - 1)
.Select(c => (new[] { e }).Concat(c)));
}
Run Code Online (Sandbox Code Playgroud)
但是这需要太长的时候k > 9。有没有一种算法可以在短时间内解决这个问题?
让我们摆脱递归并拥有512项目:
代码:
//TODO: you may want to declare it as IEnumerable<T[]> Combinations<T>
public static IEnumerable<IEnumerable<T>> Combinations<T>(
this IEnumerable<T> elements, int k) {
if (null == elements)
throw new ArgumentNullException(nameof(elements));
else if (k < 0)
throw new ArgumentOutOfRangeException(nameof(k));
T[] alphabet = elements.ToArray();
// Special cases
if (alphabet.Length <= 0)
yield break;
else if (k == 0)
yield break;
int[] indexes = new int[k];
do {
yield return indexes
.Select(i => alphabet[i])
.ToArray();
for (int i = indexes.Length - 1; i >= 0; --i)
if (indexes[i] >= alphabet.Length - 1)
indexes[i] = 0;
else {
indexes[i] += 1;
break;
}
}
while (!indexes.All(index => index == 0));
}
Run Code Online (Sandbox Code Playgroud)
演示:
string report = string.Join(Environment.NewLine, Combinations(new int[] { 1, 2}, 9)
.Select(line => string.Join(", ", line)));
Console.Write(report);
Run Code Online (Sandbox Code Playgroud)
结果:(512记录)
1, 1, 1, 1, 1, 1, 1, 1, 1
1, 1, 1, 1, 1, 1, 1, 1, 2
1, 1, 1, 1, 1, 1, 1, 2, 1
1, 1, 1, 1, 1, 1, 1, 2, 2
1, 1, 1, 1, 1, 1, 2, 1, 1
1, 1, 1, 1, 1, 1, 2, 1, 2
1, 1, 1, 1, 1, 1, 2, 2, 1
1, 1, 1, 1, 1, 1, 2, 2, 2
1, 1, 1, 1, 1, 2, 1, 1, 1
...
2, 2, 2, 2, 2, 2, 1, 2, 1
2, 2, 2, 2, 2, 2, 1, 2, 2
2, 2, 2, 2, 2, 2, 2, 1, 1
2, 2, 2, 2, 2, 2, 2, 1, 2
2, 2, 2, 2, 2, 2, 2, 2, 1
2, 2, 2, 2, 2, 2, 2, 2, 2
Run Code Online (Sandbox Code Playgroud)
让我们生成所有2**20 == 1048576项目 ( k = 20),即超过100 万个大小为 的数组20:
Stopwatch sw = new Stopwatch();
sw.Start();
int count = Combinations(new int[] { 1, 2 }, 20).Count();
sw.Stop();
Console.Write($"{count.ToString()} items at {sw.ElapsedMilliseconds:f0} milliseconds");
Run Code Online (Sandbox Code Playgroud)
结果:
1048576 items at 469 milliseconds
Run Code Online (Sandbox Code Playgroud)