使用Factoradic系统允许重复时查找Kth词典排列

时间:2017-12-10 15:44:08

标签: python algorithm math permutation factorial

当允许重复时,是否可以使用Factoradic Base System来找到第k个排列? 为了找到没有重复的Kth排列,我可以在python中做这样的事情:

def factorial(n):
    if n == 0: return 1
    return n*factorial(n-1)

def unrank(S, k, i):
    S = list(S)   # make a copy to avoid destroying the list
    n = len(S)
    nb = factorial(n) // factorial(n-k)
    print (nb)
    if i >= nb:
        raise IndexError
    res = []
    while k > 0:
        nb = nb // n
        pos = i // nb   # the factoradic digits
        i = i % nb      # the remaining digits
        res.append(S[pos])
        del S[pos]
        k = k-1
        n = n-1
    return res

res = unrank(list('ABCDEFGHJKLMNPQRSTUVWXYZ0123456789'),3, 2222)
print (res) 

查看原始post

2 个答案:

答案 0 :(得分:1)

只需在基础|S|中写出数字(即,如果是可能的字母集,则为大小)。将(某些)顺序中的集合元素用作“数字”。

作为一个例子,考虑来自list('0123456789')的三个元素的列表序列。注意它正好是从0到999的数字,如果有必要,用前导零写成三位数字。

<强>更新

以下是一些说明这个想法的Python代码:

def unrank(src, reqlen, pos):
    size = len(src)
    # it is easier to fill result from the end, so pre-create an array of the required size
    res = [src[0]] * reqlen
    for i in xrange(reqlen - 1, -1, -1):
        res[i] = src[pos % size]
        pos /= size
    if pos > 0: # this means original pos was beyond (size ** reqlen) i.e. more than the max possible index
        raise IndexError
    return res

res = unrank(list('0123456789ABCDEF'), 3, 2222)
print (res)

打印

  

['8','A','E']

您可以轻松检查0x8AE的十六进制值是否为2222

答案 1 :(得分:1)

简短回答:不,我没有看到使用Factoradic Base System做你想做的事的方法,但有一种更简单的方法。只需使用通常的数字基础。

你的术语令人困惑,因为你写了“排列”但允许重复。让我们称它们为序列,其中给函数一个检查的测试序列和保存可以使用的字符的基本序列。您希望使用基本序列中的字符在字典列表中查找相同长度的所有可能序列的测试序列计数。

为方便起见,我们假设基本序列的顺序递增且没有重复,如示例代码所示。

对于序列中的每个字符,我们想知道它在基本序列中的位置。如果碱基序列和序列都很长,那么这样做的简单方法可能是耗时的,也就是长度的乘积。有一种方法可以通过对长度之和进行排序:首先预处理基本序列以获得将每个字符映射到基本序列中的位置的字典,然后将测试序列中的每个字符转换为其中的位置。基本序列。我们现在有一个基本序列中的字符位置列表。

此列表类似于base-N数字,其中N是基本序列的长度。然后我们使用通常的方法将其转换为标准整数,这是我们期望的结果。

这是完成所有这些的一些代码。当然,还有其他方法可以做到这一点。

def sequence_position(test_seq, base_seq):
    """Return the count of the test sequence in the lexicographical
    listing of all possible sequences of the same length using the 
    items in the base sequence. Repetition of items is allowed and the 
    order of the items in the list matters.

    This function assumes the base sequence is in increasing order and
    has no repetitions.
    """
    # Create a dictionary mapping items in the base sequence to
    #   their positions in the base sequence.
    item_pos_dict = {item:pos for pos,item in enumerate(base_seq)}
    # Create a list of positions of the characters in the test sequence.
    positions = [item_pos_dict[item] for item in test_seq]
    # Convert this list of positions to its count in the lexicographical
    #   sequence of all such sequences of this length
    base = len(base_seq)
    result = 0
    for pos in positions:
        result = result * base + pos
    return result

print(sequence_position('ABC', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'))