从置换到数:
令k为字符类(例如:AAABBC具有三个字符类)的数目
设N [K]为每个字符类中元素的个数。 (例如:对于AAABBC,我们有N [K] = [3,2,1],并且让N = sum(N [K])
序列的每个合法排列然后唯一地对应于不完整的K-方式树。
置换的唯一编号,然后对应于该树的节点中的K-叉树终端节点的后序遍历的索引。
幸运的是,我们实际上并不需要执行树遍历 - 我们只需要知道树中有多少个终端节点是按字典顺序不如我们的节点。这是非常容易计算的,就像在树中的任何节点一样,数字终端节点低于当前节点等于使用序列中未使用的元素的置换数量,其具有简单的封闭形式解决方案乘积的乘法。
因此,鉴于我们的6个原始字母,并且我们的排列的第一个元素是'B',我们确定将会有5!/ 3!1!1! = 20个以'A'开始的元素,所以我们的排列数必须大于20.如果我们的第一个字母是'C',我们可以计算它为5!/ 2!2!1! (不是A)+ 5!/ 3!1!1! (不是B)= 30+ 20,或者作为 60(总计) - 5!/ 3!2!0! (C)= 50
使用此方法,我们可以进行置换(例如'BAABCA')并执行以下计算: Permuation#=(5!/ 2!2!1!)('B')+ 0('A')+ 0('A')+ 3!/ 1!1!1! ('B')+ 2!/ 1!
= 30 + 3 + 2 = 35
检查工作的:CBBAAA对应于
(5/2 2 1(未A)+ 5/3 1!!!! 1!(不是B))'C'+ 4!/ 2!2!0! (不是A)'B'+ 3!/ 2!1!0! (非A)'B'=(30 + 20)+6 + 3 = 59
同样,AAABBC = 0('A')+ 0'A'+'0'A'+ 0'B' + 0 'B' + 0 C = 0
样品实施:
import math
import copy
from operator import mul
def computePermutationNumber(inPerm, inCharClasses):
permutation=copy.copy(inPerm)
charClasses=copy.copy(inCharClasses)
n=len(permutation)
permNumber=0
for i,x in enumerate(permutation):
for j in xrange(x):
if(charClasses[j]>0):
charClasses[j]-=1
permNumber+=multiFactorial(n-i-1, charClasses)
charClasses[j]+=1
if charClasses[x]>0:
charClasses[x]-=1
return permNumber
def multiFactorial(n, charClasses):
val= math.factorial(n)/ reduce(mul, (map(lambda x: math.factorial(x), charClasses)))
return val
从数量排列: 这个过程可以反过来做,虽然我不知道如何有效地: 鉴于一个置换数字和它从中产生的字母表,递归地减去小于或等于剩余置换数字的最大数量的节点。
E.g.给定59的置换数,我们首先可以从9减去30 + 20 = 50('C')。然后我们可以减去'B'(6)和第二个'B'(3),重新产生我们原来的置换。
按定义集合不包含重复元素,例如,在集合思考中{1,2,3} == {1,2,3,2,1}'。你能澄清你的问题吗? –
@HighPerformanceMark尽管技术上正确,但它非常清楚OP的含义。 – phant0m