我正在寻找一种能够生成集合的所有排列的算法。为方便起见,该集始终为[0, 1..n]
。有很多方法可以做到这一点,并不是特别难。
我还需要的是每个排列的反转次数。 这样做的最快(就时间复杂度而言)算法是什么?
我希望有一种方法可以产生那些产生反转次数的排列作为副作用,而不会增加复杂性。
算法应该生成列表,而不是数组,但如果它在速度方面有足够大的差异,我会接受基于数组的列表。
加分( ......没有分数...... ),如果它有功能,并以纯语言实现。
答案 0 :(得分:1)
Steinhaus–Johnson–Trotter algorithm允许在排列生成期间容易地保持反转计数。摘自维基:
Thus, from the single permutation on one element,
1
one may place the number 2 in each possible position in descending
order to form a list of two permutations on two elements,
1 2
2 1
Then, one may place the number 3 in each of three different positions
for these three permutations, in descending order for the first
permutation 1 2, and then in ascending order for the permutation 2 1:
1 2 3
1 3 2
3 1 2
3 2 1
2 3 1
2 1 3
在递归的每一步,我们在较小数字列表中插入最大数字。很明显,这个插入增加了M个新的反转,其中M是插入位置(从右边开始计数)。例如,如果我们有3 1 2
个列表(2个反转),则会插入4
3 1 2 4 //position 0, 2 + 0 = 2 inversions
3 1 4 2 //position 1, 2 + 1 = 3 inversions
3 4 1 2 //position 2, 2 + 2 = 4 inversions
4 3 1 2 //position 3, 2 + 3 = 5 inversions
伪代码:
function Generate(List, Count)
N = List.Length
if N = N_Max then
Output(List, 'InvCount = ': Count)
else
for Position = 0 to N do
Generate(List.Insert(N, N - Position), Count + Position)
P.S。递归方法在这里不是强制性的,但我怀疑这对于功能性人来说是很自然的
P.P.S 如果您担心插入列表,请考虑仅使用邻居元素交换的Even's speedup section,并且每个交换递增或递减倒数计数为1.
答案 1 :(得分:1)
这是一个执行任务的算法,按每个排列分摊O(1)
,并生成一组链接列表元组,这些元组共享尽可能多的内存。
我将在未经测试的Python中实现除链接列之外的所有内容。虽然Python对于真正的实现来说是一种糟糕的语言。
def permutations (sorted_list):
answer = []
def add_permutations(reversed_sublist, tail_node, inversions):
if (0 == len(sorted_sublist)):
answer.append((tail_node, inversions))
else:
for idx, val in enumerate(reversed_sublist):
add_permutations(
filter(lambda x: x != val),
ListNode(val, tail_node,
inversions + idx
)
add_permutations(reversed(sorted_list), EmptyListNode(), 0)
return answer
您可能想知道我对所有这些复制的摊销O(1)
的主张。那是因为如果剩下m
个元素,我们会O(m)
工作,然后通过m!
元素分摊它们。因此,较高级别节点的摊销成本是每个底层呼叫的收敛成本,我们需要每个排列一个。