我有一个26个字符的字母数组A..Z。
我正在寻找一种高性能算法,该算法列出了填充长度为X的数组而没有任何重复字符的所有排列。
示例:
X = 3。目标数组:_ _ _
排列是A B C,直到Z Y X.
X = 4。目标数组:_ _ _ _
排列是A B C D,直到Z Y X W
X = 5。目标数组:_ _ _ _ _
排列是A B C D E直到Z Y X W V
(抱歉,我不知道这种算法是如何命名的)
提前致谢。
C,Delphi或Java中的代码也可以,因为它很容易翻译。
答案 0 :(得分:1)
一个简单的解决方案是递归的
char current_combination[27];
int char_used[26];
void enumerate(int i, int n)
{
for (int j=0; j<26; j++)
{
if (!char_used[j])
{
char_used[j] = 1;
current_combination[i] = 'A' + j;
if (i+1 == n)
{
puts(current_combination);
}
else
{
enumerate(i+1, n);
}
char_used[j] = 0;
}
}
}
上面的函数接受要计算的字符的索引i
和组合中字符的总数n
(代码假定为i<n
)。它保留当前组合和全局变量中已使用变量的标志数组,以避免复制它们。
例如,要生成长度为5 enumerate(0, 5)
的所有组合。
请注意,组合总数增长非常快。例如,对于n=6
,有165,765,600
个组合,输出超过1Gb。
答案 1 :(得分:0)
我会采用一种简单的蛮力方法,但是要理解排列的数量可以达到数字为26!/(26-x)!这可能是相当大的3,有15,600个排列,5个有7,893,600个排列,这不是很小。基本上你可以通过循环中的循环遍历所有值,不幸的是O(n ^ x)其中x是自循环嵌套以来导致复杂性跳跃的字符数。
要考虑的是你在这里检查复杂性有多精细。例如,虽然您可以考虑在第一对循环中变得聪明以避免重复,但是第三个循环变得有点棘手,但是如果您开始使用26个字母的List并删除之前的循环,这将使最后一个循环是一个简单的迭代,因为你知道没有任何重复,虽然这对于在外循环的每次传递中必须复制列表所消耗的内存而言可能是昂贵的。因此,第一次,您将通过AB_然后AC_等等,但复制列表可能是在操作方面变得昂贵的地方,因为有数千次复制列表,人们可能会想知道如果这比做比较更有效。
答案 2 :(得分:0)
您确定要查看所有排列吗?如果你有X = 3,你将有26 * 25 * 24组合= 15600.如果X = 5组合数等于7893600。
您需要随机选择一个字母(或数组索引)并将其存储在某个位置,并且在每次迭代时,您应该检查是否已在上一次迭代中选择了该字母(或索引)。在此之后,您将获得长度为X个字符的随机序列。你也需要存储它。然后你需要重新考虑上一步所做的所有操作,你还要检查是否有随机顺序,你现在已经生成了子序列。
或者您可以使用直接枚举。
抱歉英语不太满意。我试着说清楚。
我希望它会有用。