我正在尝试创建一个方法,可以输出单词,其中每个字母可以是给定集合中的任何字母。例如:
First letter can be: A or B
Second letter can be AB or C
Third letter can be ABC or D
Fourth letter can be AB or C
等等。 我将输入数据存储为二维数组,如下所示:
AB
ABC
ABCD
ABC
ABC
它应该能够生成如下字样:
AAAAA
BAAAA
ABAAA
etc.
使用多维数组调用方法,如下所示:
void printAllCombinations(int[,] arr)
{
// Method code.
}
我希望能够使用任何长度和高度的多维数组调用此方法。我已经尝试过使用for循环,但是在彼此之间有太多for循环并不是最好的解决方案。
我尝试过的东西:
private static List<string> combinations(string[][] twoDimStringArray)
{
// keep track of the size of each inner String array
int[] sizeArray = new int[twoDimStringArray.Length];
// keep track of the index of each inner String array which will be used
// to make the next combination
int[] counterArray = new int[twoDimStringArray.Length];
// Discover the size of each inner array and populate sizeArray.
// Also calculate the total number of combinations possible using the
// inner String array sizes.
int totalCombinationCount = 1;
for (int i = 0; i < twoDimStringArray.Length; ++i)
{
sizeArray[i] = twoDimStringArray[i].Length;
totalCombinationCount *= twoDimStringArray[i].Length;
}
// Store the combinations in a List of String objects
List<String> combinationList = new List<string>(totalCombinationCount);
StringBuilder sb; // more efficient than String for concatenation
for (int countdown = totalCombinationCount; countdown > 0; --countdown)
{
// Run through the inner arrays, grabbing the member from the index
// specified by the counterArray for each inner array, and build a
// combination string.
sb = new StringBuilder();
for (int i = 0; i < twoDimStringArray.Length; ++i)
{
sb.Append(twoDimStringArray[i][counterArray[i]]);
}
combinationList.Add(sb.ToString()); // add new combination to list
// Now we need to increment the counterArray so that the next
// combination is taken on the next iteration of this loop.
for (int incIndex = twoDimStringArray.Length - 1; incIndex >= 0; --incIndex)
{
if (counterArray[incIndex] + 1 < sizeArray[incIndex])
{
++counterArray[incIndex];
// None of the indices of higher significance need to be
// incremented, so jump out of this for loop at this point.
break;
}
// The index at this position is at its max value, so zero it
// and continue this loop to increment the index which is more
// significant than this one.
counterArray[incIndex] = 0;
}
}
return combinationList;
}
有效的方法是什么?
答案 0 :(得分:1)
您需要找到cartesian product 所有字符列表。如comment中所述,这具有O(N^M)
复杂度,其中 N =每组中的字母, M =设置计数。毋庸置疑,计算时间很快就会出现。
我写了一个泛型扩展方法,它使用带yield return
的递归迭代器方法。它可用于查找任何数据类型的完整笛卡尔积,而不仅仅是char
。 我很感兴趣,如果可以去除它。
<强>实施强>
public static class MultiCartesianExtension
{
public static IEnumerable<TInput[]> MultiCartesian<TInput>(this IEnumerable<IEnumerable<TInput>> input)
{
return input.MultiCartesian(x => x);
}
public static IEnumerable<TOutput> MultiCartesian<TInput, TOutput>(this IEnumerable<IEnumerable<TInput>> input, Func<TInput[], TOutput> selector)
{
var inputList = input.ToList();
var buffer = new TInput[inputList.Count];
var results = MultiCartesianInner(inputList, buffer, 0);
var transformed = results.Select(selector);
return transformed;
}
private static IEnumerable<TInput[]> MultiCartesianInner<TInput>(IList<IEnumerable<TInput>> input, TInput[] buffer, int depth)
{
foreach (var current in input[depth])
{
buffer[depth] = current;
if (depth == buffer.Length - 1)
{
var bufferCopy = (TInput[])buffer.Clone();
yield return bufferCopy;
}
else
{
foreach (var a in MultiCartesianInner(input, buffer, depth + 1))
{
yield return a;
}
}
}
}
<强>用法:强>
var input = new string[]
{
"AB",
"123",
"@#",
};
foreach (var result in input.MultiCartesian(x => new string(x)))
{
Console.WriteLine(result);
}
// Results:
// A1@
// A1#
// A2@
// A2#
// A3@
// A3#
// B1@
// B1#
// B2@
// B2#
// B3@
// B3#
对于您的特定情况,可以通过不创建bufferCopy
并返回buffer
本身来提高效率。我这样做是为了确保通用的使用安全性。这是因为要正常运行,buffer
需要从外部不加修改。