这是我的问题陈述:
我可以使用哪种算法?
我的第一个想法是将我的字符串转换为数字,然后对它们进行操作(我想到哈希函数),但我不确定是什么公式可以给我结果。
有什么建议吗?
答案 0 :(得分:2)
你有2 ^ 333个可能的输入集((26 * 10 ^ 3)选择30)。
这意味着您需要一个333位宽的整数来表示所有可能性。您最多只有256位,因此会发生冲突。
这是哈希函数的典型应用程序。存在用于各种目的的哈希,因此选择正确的类型非常重要:
用于基于存储桶的数据结构(字典)的简单哈希函数必须快速。碰撞不仅是容忍的,而且是通缉的。散列的大小(以位为单位)通常很小。由于冲突,这种类型的哈希不适合您的目的。
校验和尝试避免冲突并且速度相当快。如果它足够大,这对你的情况就足够了。
加密哈希具有无法(或非常难)找到冲突的特征(即使已知输入和哈希)。它们也是不可逆的(从散列中它不可能找到输入)。这些通常是计算上昂贵的,并且对您的用例来说太过分了。
唯一标识任意输入的哈希值,如CityHash和SpookyHash,专为快速哈希和无冲突识别而设计。
SpookyHash似乎是您用例的好选择。它的宽度为128位,这意味着您需要2 ^ 64个不同的输入才能获得50%的单次碰撞机会。
它也很快:每个周期三个字节比md5或sha1快几个数量级。 SpookyHash在公共领域可用(参见上面的链接)。
要在您的用例中应用任何哈希,您可以将列表中的项目转换为数字,但将它们作为字符串提供似乎更容易。在这种情况下你必须满足编码(ASCII会这样做。)
我通常使用UTF8左右,当I18N出现问题时。那么关注规范化有时很重要。但这不适用于您的简单用例。
答案 1 :(得分:1)
哈希不会起作用,因为它可能会产生冲突。必须将每个有效输入位映射到输出位。
对于这封信,您有90 - 65 = 25个不同的值,因此您可以使用5位来表示该字母。
3位数字有1000个不同的值,所以你需要10位。
如果组合这些位,则从输入到15位数字具有唯一的映射。
这种方法很简单,但它可能会浪费一些东西。如果输出必须尽可能短,则可以按如下方式进行映射:
output = (L - 'A')*1000 + N
其中L
是字母值,'A'
是字母A的值,N
是3位数字。然后你可以使用尽可能少的位来表示output
的完整范围,即25 * 1000 - 1 = 24999.这里再次是15位,所以简单的方法不会浪费空间。
如果输出位少于输入位,则需要散列函数。我强烈建议将字符串映射到上面的二进制数据,并使用一个简单的函数将输入映射到输出,原因如下:
通用散列函数无法区分输入位,因为它对其含义一无所知。
对于256个输出位,在散列5.7e38值后,碰撞的几率为75%。资料来源:Birthday Attack。
5.7e38似乎很大,但它只对应129位(2 ^ 129 = 6.8e38)。在这种情况下,这意味着有超过 75%的可能性,存在一对 9 (129/15 = 8.6)元素的字符串强烈的>碰撞。
另一方面,如果您使用非常简单的映射功能,例如:
你可以保证任意两个字符串之间没有碰撞,最多 17个元素。
优化用于生成唯一ID的散列函数可能比通用散列表现得更好,但我怀疑它们可以保证所有256位值的无冲突散列。
结论:如果大多数输入字符串的元素少于17个,我宁愿使用哈希值。