Algorithm 给定一个置换';s的字典编号,是否有可能在O(1)中获得其中的任何项目
我想知道下面解释的任务在理论上是否可行,如果可能的话,我该如何做 给您一个Algorithm 给定一个置换';s的字典编号,是否有可能在O(1)中获得其中的任何项目,algorithm,encryption,permutation,combinatorics,number-theory,Algorithm,Encryption,Permutation,Combinatorics,Number Theory,我想知道下面解释的任务在理论上是否可行,如果可能的话,我该如何做 给您一个N元素的空间(即0和N-1之间的所有数字),让我们看看该空间上所有排列的空间,并称之为s。可以标记为S[i]的i的S成员是字典编号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 (当然,当看到一个大的N时,这个空间会变得非常大,N!) 现在,我已经知道了,
N
元素的空间(即0
和N-1
之间的所有数字),让我们看看该空间上所有排列的空间,并称之为s
。可以标记为S[i]
的i
的S成员是字典编号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
(当然,当看到一个大的N
时,这个空间会变得非常大,N!
)
现在,我已经知道了,但我想要更好的
有些排列本身可能是巨大的。例如,如果您正在查看N=10^20
。(S
的大小应该是(10^20)!
,这是我在堆栈溢出问题中提到的最大数字:)
如果你只看空间中的一个随机排列,那么它将非常大,以至于你无法将整个内容存储在硬盘上,更不用说通过字典数字计算每个项目了。我想要的是能够对该排列进行项目访问,并获得每个项目的索引。也就是说,给定指定排列的N
和i
,一个函数获取索引号并查找驻留在该索引中的数字,另一个函数获取数字并查找其驻留在哪个索引中。我想在O(1)
中这样做,所以我不需要存储或迭代排列中的每个成员
你说疯了?不可能的?可能是这样。但是请考虑一下:块密码,比如AES,本质上是一个排列,它几乎完成了我上面概述的任务。AES的块大小为16字节,这意味着N
是256^16
,大约是10^38
。(并非重要的是,S的大小是惊人的(256^16)!
,或者大约10^8507059173023461585843651857942052838
,这打破了我最近的“堆栈溢出上提到的最大数量”记录:
每个AES加密密钥在N=256^16
上指定一个排列。这种排列不能全部存储在你的计算机上,因为它的成员比太阳系中的原子还要多。但是,它允许您访问项目。通过使用AES加密数据,您可以逐块查看数据,对于每个块(范围(N)
)的成员,您可以输出加密的块,范围(N)
的成员位于排列中原始块的索引号中。当你解密的时候,你在做相反的事情(找到一个块的索引号)。我相信这是在O(1)
中完成的,我不确定,但无论如何它都非常快
使用AES或任何其他分组密码的问题是,它将您限制在非常特定的N
,并且它可能只捕获可能的排列的一小部分,而我希望能够使用我喜欢的任何N
,并对我喜欢的任何排列S[I]
进行项目访问
在给定大小N
和排列编号i
的情况下,是否可以对排列进行O(1)
项目访问?如果是,怎么做
(如果我有幸在这里得到代码答案,如果它们是Python的,我将不胜感激。)
更新:
一些人指出了一个令人悲哀的事实,即排列数字本身将是如此巨大,以至于仅仅读取数字就会使任务变得不可行。然后,我想修改我的问题:如果可以访问排列的字典编号,是否可以在O(尽可能小)中获得排列中的任何项目?您的问题有点没有意义,因为任意排列索引的输入大小有大小日志(N!)(假设你想表示所有可能的置换),也就是θ(N logn),所以如果N真的很大,那么仅仅读取置换索引的输入将花费太长的时间,肯定比O(1)长得多。存储置换索引的方式可能是,如果你已经存储了它,那么你可以访问O中的元素(1) 但可能任何这样的方法都相当于将置换存储在连续内存中(也有θ(N logn)大小),如果将置换直接存储在内存中,那么假设可以进行O(1)内存访问,问题就变得微不足道了。(但是,您仍然需要考虑元素的位编码的大小,即O(logn)) 根据加密类比的精神,也许您应该根据某些属性指定置换的一小部分,并询问是否可以对该小部分进行O(1)或O(logn)元素访问。编辑: 我误解了这个问题,但它并不是在浪费。我的算法让我明白:置换的字典数字的factoradic表示几乎与置换本身相同。事实上,factoradic表示的第一个数字与对应置换的第一个元素相同(假设您的空间由0到N-1的数字组成)。知道这一点,存储索引而不是排列本身并没有意义。要了解如何将词典数字转换为排列,请阅读下面的内容。 另见 原创帖子: 在S空间中,有N个元素可以填充第一个槽,这意味着有(N-1)!个元素以0开头。因此,i/(N-1)!是第一个元素(我们称之为“a”)。以0开头的S的子集由(N-1)!个元素组成。这些是集合N{a}的可能排列。现在您可以
find_by_index(List N, int i){
String str = "";
for(int l = N.length-1; i >= 0; i--){
int pos = i/fact(l);
str += N.get(pos);
N.remove(pos);
i %= fact(l);
}
return str;
}
find_index(String str){
OrderedList N;
int i = 0;
for(int l = str.length-1; l >= 0; l--){
String item = str.charAt(l);
int pos = N.add(item);
i += pos*fact(str.length-l)
}
return i;
}
def getPick(fact_num_list):
"""fact_num_list should be a list with the factorial number representation,
getPick will return a tuple"""
result = [] #Desired pick
#This will hold all the numbers pickable; not actually a set, but a list
#instead
inputset = range(len(fact_num_list))
for fnl in fact_num_list:
result.append(inputset[fnl])
del inputset[fnl] #Make sure we can't pick the number again
return tuple(result)
import math
def base10_baseFactorial(number):
"""Converts a base10 number into a factorial base number. Output is a list
for better handle of units over 36! (after using all 0-9 and A-Z)"""
loop = 1
#Make sure n! <= number
while math.factorial(loop) <= number:
loop += 1
result = []
if not math.factorial(loop) == number:
loop -= 1 #Prevent dividing over a smaller number than denominator
while loop > 0:
denominator = math.factorial(loop)
number, rem = divmod(number, denominator)
result.append(rem)
loop -= 1
result.append(0) #Don't forget to divide to 0! as well!
return result