如何使用整数唯一标识一组字符串

时间:2015-09-16 10:12:18

标签: string algorithm language-agnostic uniqueidentifier

这是我的问题陈述:

  • 我有一组与正则表达式匹配的字符串。让我们说它匹配[A-Z] [0-9] {3}(即1个字母和3个数字)。
  • 我可以在1到30之间有任意数量的字符串。例如,我可以:
    • {A123}
    • {A123,B456}
    • {Z789,D752,E147,...,Q665}
    • ...
  • 我需要生成一个整数(实际上我可以使用256位),对于任何字符串集都是唯一的,无论元素的数量是多少(尽管可以使用元素的数量来生成整数)

我可以使用哪种算法?

我的第一个想法是将我的字符串转换为数字,然后对它们进行操作(我想到哈希函数),但我不确定是什么公式可以给我结果。

有什么建议吗?

2 个答案:

答案 0 :(得分:2)

你有2 ^ 333个可能的输入集((26 * 10 ^ 3)选择30)。

这意味着您需要一个333位宽的整数来表示所有可能性。您最多只有256位,因此会发生冲突。

这是哈希函数的典型应用程序。存在用于各种目的的哈希,因此选择正确的类型非常重要:

  • 用于基于存储桶的数据结构(字典)的简单哈希函数必须快速。碰撞不仅是容忍的,而且是通缉的。散列的大小(以位为单位)通常很小。由于冲突,这种类型的哈希不适合您的目的。

  • 校验和尝试避免冲突并且速度相当快。如果它足够大,这对你的情况就足够了。

  • 加密哈希具有无法(或非常难)找到冲突的特征(即使已知输入和哈希)。它们也是不可逆的(从散列中它不可能找到输入)。这些通常是计算上昂贵的,并且对您的用例来说太过分了。

  • 唯一标识任意输入的哈希值,如CityHashSpookyHash,专为快速哈希和无冲突识别而设计。

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)元素的字符串碰撞。

另一方面,如果您使用非常简单的映射功能,例如:

  • 将输入截断为256位(使用前15个元素,每个15位)
  • 使所有15位元素的256位xor值

你可以保证任意两个字符串之间没有碰撞,最多 17个元素

优化用于生成唯一ID的散列函数可能比通用散列表现得更好,但我怀疑它们可以保证所有256位值的无冲突散列。

结论:如果大多数输入字符串的元素少于17个,我宁愿使用哈希值。