我想知道下面解释的任务在理论上是否可行,如果可以,我该怎么做。
给定一个N
元素空间(即 和 之间的所有数字0
。N-1
)让我们看看该空间上所有排列的空间,并将其称为S
。的i
第 th 个成员S
,可以被标记S[i]
,是带有字典序号的排列i
。
例如,如果N
是 3,那么S
是这个排列列表:
S[0]: 0, 1, 2
S[1]: 0, 2, 1
S[2]: 1, 0, 2
S[3]: 1, 2, 0
S[4]: 2, 0, 1
S[5]: 2, 1, 0
(当然,当看一个 big 时N
,这个空间变得非常大,N!
确切地说。)
现在,我已经知道如何通过索引号获取排列i
,并且我已经知道如何进行相反的操作(获取给定排列的字典序号。)但我想要更好的东西。
一些排列本身可能是巨大的。例如,如果您正在查看N=10^20
. (S
我(10^20)!
认为这是我在 Stack Overflow 问题中提到的最大数字:)
如果您只是查看该空间上的随机排列,那么它会太大以至于您无法将整个内容存储在硬盘上,更不用说按字典序号计算每个项目了。我想要的是能够对该排列进行项目访问,并获得每个项目的索引。也就是说,给定N
并i
指定一个排列,有一个函数接受一个索引号并找到驻留在该索引中的数字,另一个函数接受一个数字并找到它所在的索引。我想在 中执行此操作O(1)
,因此我不需要存储或迭代排列中的每个成员。
疯了,你说?不可能的?那可能。但是考虑一下:像 AES 一样的分组密码本质上是一种排列,它几乎可以完成我上面概述的任务。AES 的块大小为 16 字节,这意味着N
大约. (无关紧要的大小是一个惊人的,或大约,这超过了我最近的“堆栈溢出中提到的最大数字”的记录:)256^16
10^38
S
(256^16)!
10^85070591730234615865843651857942052838
每个 AES 加密密钥在N=256^16
. 这种排列不能完整地存储在你的计算机上,因为它的成员比太阳系中的原子还多。但是,它允许您访问项目。通过使用 AES 加密数据,您可以逐块查看数据,并且对于每个块(的成员range(N)
)输出加密块,该加密块的成员range(N)
位于排列中原始块的索引号中。当你解密时,你正在做相反的事情(查找一个块的索引号。)我相信这是在 中完成的O(1)
,我不确定,但无论如何它非常快。
使用 AES 或任何其他分组密码的问题在于它将您限制在非常具体的范围内N
,并且它可能只捕获一小部分可能的排列,而我希望能够使用任何N
我喜欢的,并在任何我喜欢的排列S[i]
。
是否可以在给定大小和排列数O(1)
的排列上获得项目访问权限?如果是这样,怎么做?N
i
(如果我有幸在这里得到代码答案,如果他们会在 Python 中,我将不胜感激。)
更新:
一些人指出了一个可悲的事实,即排列数字本身会如此巨大,以至于仅读取数字会使任务不可行。然后,我想修改我的问题:如果可以访问排列的字典序数的阶乘表示,是否有可能在 O 中获得排列中的任何项目(尽可能小)?