给定字典序索引的多重集合排列算法
我正在寻找一种高效的算法,用来根据给定的索引找到一个多重集合的排列。
举个例子,给定一个集合{1, 3, 3}
。所有的排列按字典顺序排列是{133, 313, 331}
。这些元素的索引是{0, 1, 2}
。如果给定index=2
,那么结果就是331。
我找到了一种算法,可以根据字典索引找到一个集合的排列。这个算法效率很高:O(n^2)。
不过,这个算法是在一个正常的集合上测试的(比如{1, 2, 3}
),而在我的测试中并不正确。我在这里描述他的python代码,方便你理解。
from math import factorial, floor #// python library
from math import factorial, floor #// python library
i=5 #// i is the lexicographic index (counting starts from 0)
n=3 #// n is the length of the permutation
p = range(1,n+1) #// p is a list from 1 to n
for k in range(1,n+1): #// k goes from 1 to n
d = i//factorial(n-k) #// use integer division (like division+floor)
print(p[d]),
p.remove(p[d]) #//delete p[d] from p
i = i % factorial(n-k) #// reduce i to its remainder
1 个回答
5
# Python 2
from collections import Counter
from math import factorial
def count_permutations(counter):
values = counter.values()
return (
factorial(sum(values))/reduce(lambda a, v: a * factorial(v), values, 1)
)
def permutation(l, index):
l = sorted(l)
if not index:
return l
counter = Counter(l)
total_count = count_permutations(counter)
acc = 0
for i, v in enumerate(l):
if i > 0 and v == l[i-1]:
continue
count = total_count * counter[v] / len(l)
if acc + count > index:
return [v] + permutation(l[:i] + l[i + 1:], index - acc)
acc += count
raise ValueError("Not enough permutations")
看起来运行得很正常
In [17]: for x in range(50): print x, permutation([1, 1, 2, 2, 2], x)
0 [1, 1, 2, 2, 2]
1 [1, 2, 1, 2, 2]
2 [1, 2, 2, 1, 2]
3 [1, 2, 2, 2, 1]
4 [2, 1, 1, 2, 2]
5 [2, 1, 2, 1, 2]
6 [2, 1, 2, 2, 1]
7 [2, 2, 1, 1, 2]
8 [2, 2, 1, 2, 1]
9 [2, 2, 2, 1, 1]
10---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
[...]
ValueError: Not enough permutations
时间复杂度:O(n^2)
。