This problem can be easily solved by its first simplification and recursive thinking.
So, first suppose that all elements in the input sequence are unique, then the set of “unique” permutations is just a set of permutations.
Now, to find the rank of a sequence a_1, a_2, a_3, ..., a_nin our set of permutations, we can:
Sort the sequence to get b_1, b_2, ..., b_n. This permutation, by definition, has a rank 0.
a_1 b_1. , : a_1, a_2, ..., a_n , a_2, ..., a_n.
b_1 < a_1, , b_1, a_1, a_2, ..., a_n. , (n-1)! = (n-1)*(n-2)*(n-3)*...*1.
b_1, ..., b_n. b_2 < a_1, , b_2, .
(n-1)! .
, j b_j == a_j, 2.
:
import math
def permutation_rank(seq):
ref = sorted(seq)
if ref == seq:
return 0
else:
rank = 0
f = math.factorial(len(seq)-1)
for x in ref:
if x < seq[0]:
rank += f
else:
rank += permutation_rank(seq[1:]) if seq[1:] else 0
return rank
:
In [24]: import string
...: import random
...: seq = list(string.ascii_lowercase)
...: random.shuffle(seq)
...: print(*seq)
...: print(permutation_rank(seq))
...:
r q n c d w s k a z b e m g u f i o l t j x p h y v
273956214557578232851005079
: , , , (n-1)! - , . n, s_1, ..., s_k s_j c_j , `(n-1)!/(c_1! * c_2! *... * c_k!).
, (n-1)! , c_t , .
:
import math
from collections import Counter
from functools import reduce
from operator import mul
def permutation_rank(seq):
ref = sorted(seq)
counts = Counter(ref)
if ref == seq:
return 0
else:
rank = 0
f = math.factorial(len(seq)-1)
for x in sorted(set(ref)):
if x < seq[0]:
counts_copy = counts.copy()
counts_copy[x] -= 1
rank += f//(reduce(mul, (math.factorial(c) for c in counts_copy.values()), 1))
else:
rank += permutation_rank(seq[1:]) if seq[1:] else 0
return rank
, counts, , .
, :
In [44]: for i,x in enumerate(sorted(set(it.permutations('aabc')))):
...: print(i, x, permutation_rank(x))
...:
0 ('a', 'a', 'b', 'c') 0
1 ('a', 'a', 'c', 'b') 1
2 ('a', 'b', 'a', 'c') 2
3 ('a', 'b', 'c', 'a') 3
4 ('a', 'c', 'a', 'b') 4
5 ('a', 'c', 'b', 'a') 5
6 ('b', 'a', 'a', 'c') 6
7 ('b', 'a', 'c', 'a') 7
8 ('b', 'c', 'a', 'a') 8
9 ('c', 'a', 'a', 'b') 9
10 ('c', 'a', 'b', 'a') 10
11 ('c', 'b', 'a', 'a') 11
, :
In [45]: permutation_rank('zuibibzboofpaoibpaybfyab')
Out[45]: 246218968687554178