我正在寻找一种可以从已经发生的洗牌过程中导出密钥的算法。
假设我们已经改组了字符串“Hello”:
"hello" -> "loelh"
现在我想从中导出一个键k
,我可以使用它来撤消改组。因此,如果我们使用k
作为确定性混洗算法的输入参数(例如Fisher-Yates和shuffle "loelh"
),我们将恢复初始字符串"hello"
。
我的意思并不是简单地使用一个相同的确定性改组算法来进行混洗和去混洗。那是因为在我的情况下,第一个字符串在经典意义上不会被真正洗牌。实际上会有两组数据(字节或位数组)刚刚给出,我们希望从第一个到第二个只用一个之前得到的密钥。
我希望很清楚我想要实现的目标,并且我会感谢所有提示或建议的解决方案。
此致 梅里特
更新
另一个尝试: 基本上,人们也可以称之为一堆数据的确定性转换,例如一个字节数组,但我会坚持使用“hello”-string示例。
假设我们有一个转换算法transform(data, "unknown seed")
,其中data
是“你好”而unknown seed
是我们正在寻找的。 transform
的结果是“loelh”。我们正在寻找这种“未知的种子”,我们可以用它来扭转这一过程。在“未知种子”生成时,输入数据和结果当然都是已知的。
稍后我想使用“未知种子”(应该已知;-)再次获取原始字符串:因此transform("loelh", seed)
应再次导致"hello"
。
所以你也可以把它看作是data*["unknown value"]=resultdata
之类的等式,我们试图找到未知值(运算符*
可以是任何类型的运算)。
答案 0 :(得分:4)
首先,让我们大大简化问题。我们假设您总是在“abcde”上进行排列,而不是置换“你好”,因为这样可以更容易理解。
shuffle 随机生成排列。 shuffle如何产生排列是无关紧要的; shuffles会产生排列,这就是我们需要知道的。
让我们将排列状态表示为包含数字1到5的字符串。假设shuffle产生排列“21453”。也就是说,我们将第一个字母放在第2位:_a___
。我们将第二个字母放在第1位,ba___
。我们把第3个字母放在第5位:ab__c
。我们取第四个字母并将其放在第3位bad_c
,然后我们将第五个字母放在第4位,badec
。
现在,您希望推导出一个“密钥”,它允许您“排除”排列。嗯,这只是另一种排列,称为逆置换。要计算“21453”的逆置换,请执行以下操作:
现在读下第二栏; “21453”的逆排列是“21534”。我们正在取消“badec”。我们将第一个字母放在第2位:_b___
。我们将第二个字母放在第1位:ab___
。我们将第三个字母放在第4位:ab_d_
。我们把第四个字母放在第5位:ab_de
。我们将第五个字母放在第3位:abcde
。
答案 1 :(得分:1)
改组只是创建给定序列的随机排列。这样做的典型方法就像您指出的Fisher-Yates Shuffle。问题是随机播放程序根据种子生成多个随机数,除非你实现随机数生成器,否则没有简单的方法来反转随机数序列。
还有另一种方法可以做到这一点。如果您可以直接生成序列的第n个排列怎么办?也就是说,给定字符串“Fast”,您将前几个排列定义为:
0 Fast
1 Fats
2 Fsat
3 Fsta
... etc. for all 24 permutations
您想要对这四个字符进行随机排列。选择0到23之间的随机数,然后调用函数生成该排列。
如果你知道密钥,你可以调用另一个函数,再次传递该密钥,让它将排列反转回原来。
在他fourth article的series on permutations中,Eric Lippert展示了如何生成第n个排列而不必生成所有排列的排列。他没有说明如何逆转这个过程,但如果你了解发电机是如何工作的,那么这样做应该不难。值得花时间学习整篇文章。
如果您不知道密钥(即使用的随机数)是多少,那么导出到达原始订单所需的互换顺序是很昂贵的。
经过反思,如果给出原始序列和转换后的序列,则可能可以导出密钥。由于您知道每个符号移动了多远,因此您应该能够导出密钥。考虑两个字母的可能排列:
0. ab 1. ba
现在,将字母b
分配给0,将字母a
分配给值1.什么排列数是ba
?在字符串中查找a
,向左交换,直到它到达正确的位置,然后将交换次数乘以1.
这太容易了。考虑下一个:
0. abc 1. acb 2. bac
3. cab 4. bca 5. cba
a
现在为2,b
为1,c
为0.鉴于cab
:
swap a left one space. 1x2 = 2. Result is `acb`
swap b left one space. 1x1 = 1. Result is `abc`
所以cab
是排列#3。
这确实假设您的置换生成器以相同的方式对排列进行编号。它也不是一种非常有效的做事方式。最坏情况需要n(n-1)/2
掉期。您可以通过移动数组中的内容来优化交换,但它仍然是O(n ^ 2)算法。其中n
是序列的长度。 100或甚至1,000件物品并不可怕。不过那之后很糟糕。