我一直试图在一个简单的列表中置换我拥有的项目,并且我使用了这个question中的代码,但是当序列的大小变得非常大时,它非常慢。
static IEnumerable<IEnumerable<T>>
GetPermutations<T>(IEnumerable<T> list, int length)
{
if (length == 1) return list.Select(t => new T[] { t });
return GetPermutations(list, length - 1)
.SelectMany(t => list.Where(e => !t.Contains(e)),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
例如,当输出长度需要很大时,此方法需要很长时间才能执行。
问题的一个例子是,我们有25个字母表,我们想知道我们可以用它们生成的所有可能的5-charterer长字。
还有其他方法可以比这更快地运行吗?
答案 0 :(得分:1)
假设你有25个字母,并且你想知道你可以用它们生成多少单词,这些单词正好是5个字符,那么在数学上会有25^5
种可能性。为简化这一点,我们可以将问题描述为:
[25] [25] [25] [25] [25]
这将类似于异国情调的基地(在这种情况下它是基地25)。我认为你能做的最快的方法就是利用基本转换。让我们将字母数组的大小缩短为5,将单词的长度缩短为2个字符,以使问题更简单。您必须计算在这种情况下有多少种可能性[5] [5] -> 25
。既然你知道这一点,你可以使用类似于以下方法的东西:
public static T[] Permute<T>(int input, List<T> items)
{
List<T> brute = new List<T>();
while (true)
{
var temp = (decimal)input / (decimal)items.Count;
var r = input % items.Count;
input = (int)temp-1;
if (temp < 1)
{
brute.Add(items[r]);
break;
}
else
{
brute.Add(items[r]);
}
}
return brute.ToArray();
}
并在for循环中使用它来获得所需的输出:
static void Main(string[] args)
{
List<char> ls = new List<char> { 'A', 'B', 'C', 'D', 'E' };
for (int i = ls.Count; i < (ls.Count * ls.Count)+ls.Count ; i++) {
var x = Permute(i, ls);
for (int j = 0; j < x.Length; j++) {
Console.Write(x[j] + " ");
}
Console.WriteLine();
}
Console.ReadKey(true);
}
请注意,您最好使用Math.Pow
方法而不是(ls.Count * ls.Count)
,具体取决于输出的时长。并且您必须计算for循环中的偏移量,以便获得所需字符串的确切大小。
这种方法100%依赖于基本转换,就好像你有5个字母并且你有两个位置,然后用五个字母填充第一个位置,然后因为没有第6个,所以第一个必须放到另一个地方并且必须一次又一次地重复相同的过程。