让我重申我认为你的意思的问题。
您有一个长度为n-1 的位串。如果它的数字是增加/减少的模式,则描述了一组适合该模式的排列。该集合可以按升序排列。
你希望能够解决两个问题。
- 给定一个适合模式的排列,说出它在该顺序中的位置(即“排列”它)
- 给定一个数字,产生在该位置的排列顺序(即“取消排序”它)
理想情况下,您希望能够解决这些问题,而不必生成所有符合模式的排列。
两者的关键在于以下功能:
def count_matching (bitstring, start):
''' Returns how many permutations of 1..(len(bitstring) + 1)
''' match bitstring with starting value start
# some implementation here.
这可以很容易地递归计算。然而,以天真的方式这样做会产生所有排列。但是,如果我们给memoize 添加一个缓存层,那么我们会存储多项式数量的数据并进行多项式调用来填充它。
这是为您的示例缓存后获得的数据:
{
('010', 1): 2,
('010', 2): 2,
('010', 3): 1,
('010', 4): 0,
('10', 1): 0,
('10', 2): 1,
('10', 3): 1,
('0', 1): 1,
('0', 2): 0,
('', 1): 1
}
现在这似乎是针对少数模式的大量数据。但是对于长度为n 的排列,条目的数量会像O(n^2) 一样增长,并且填充它的调用数量会像O(n^3) 一样增长。 (任何眼尖的读者都可能想出如何及时填充它O(n^2)。我将使用简单版本。)
有了这个,我们可以根据以下想法进行排名并确定它必须是哪种排列。
假设我们想要找到秩为 4 的排列。我们的起始号码列表是(1 2 3 4)。我们可以跳过以('010', 1) 开头的0 个排列,答案将是('010', 2) 的2 个排列中的第二个。
取第二个数字2,我们的部分排列是[2,我们有数字(1 3 4)。我们正在寻找位串'10' 的第二个。我们跳过以('10', 1) 开头的0 个排列,以('10', 2) 开头的1,并希望以('10', 3) 开头的1 中的第一个。
取第三个数字4,我们的部分排列是[2, 4,我们有数字(1 3)。和之前一样,我们发现我们想要('0', 1) 中的第一个。
取第一个数字1,我们的部分排列是[2, 4, 1,我们有数字(3)。选择不多。
所以我们完成并得到[2, 4, 1, 3]。您可以验证的是第 4 个。
所以我们以[2, 4, 3, 1] 结束。
我们也可以走另一条路。采用相同的排列,我们从[2, 4, 3, 1] 开始并想要它的排名。
在它之前有多少位在第一位不同?它使用了第二个可能的第一个数字。从 ('010', 1) 的条目我们知道有 2 个。剩下的数字是 1 3 4。
它前面有多少个第二位数不同?它使用第三个可能的第二个数字。从 ('10', 1) 和 ('10', 2) 的条目中,我们知道它前面还有 1 个。
我们现在有号码1 3。第三位数字没有出现在它之前。再一次,最后没有。
前面有3,它必须有等级4。
你有它。为了记忆一个递归函数,您现在可以直接按等级查找排列,或对给定排列进行排序。