【问题标题】:How to uniquely identify a set of strings using an integer如何使用整数唯一标识一组字符串
【发布时间】:2015-12-12 20:51:54
【问题描述】:

这是我的问题陈述:

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

我可以使用哪种算法?

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

有什么建议吗?

【问题讨论】:

    标签: string algorithm language-agnostic uniqueidentifier


    【解决方案1】:

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

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

    这是散列函数的典型应用。哈希值有多种用途,因此选择正确的类型很重要:

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

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

    • 加密哈希的特点是不可能(或很难)找到冲突(即使输入和哈希都已知)。而且它们是不可逆的(从散列中无法找到输入)。对于您的用例,这些通常计算成本高且过大。

    • 用于唯一识别任意输入的散列,例如 CityHashSpookyHash,专为快速散列和无冲突识别而设计。

    SpookyHash 似乎是您的用例的不错选择。它是 128 位宽,这意味着您需要 2^64 个不同的输入才能获得 50% 的单次碰撞机会。

    它也很快:每个周期三个字节比 md5 或 sha1 快几个数量级。 SpookyHash 在公共领域可用(见上面的链接)。

    要对您的用例应用任何哈希,您可以将列表中的项目转换为数字,但将它们作为字符串提供似乎更容易。在这种情况下,您必须接受编码(ASCII 可以)。

    当 I18N 成为问题时,我通常使用 UTF8 左右。然后,关注规范化有时很重要。但这不适用于您的简单用例。

    【讨论】:

    • 感谢您的回答。我会朝这个方向看。
    【解决方案2】:

    哈希不起作用,因为它可能会产生冲突。每个有效输入位都必须映射到一个输出位。

    对于字母,您有 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) 元素的字符串 strong> 碰撞。

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

    • 将输入截断为 256 位(使用每个 15 位的前 17 个元素)
    • 对所有 15 位元素进行 256 位异或值

    您可以保证最多 17 个元素的任意两个字符串之间没有冲突。

    与此处相比,针对生成唯一 ID 进行优化的散列函数可能比通用散列执行得更好,但我怀疑它们能否保证所有 256 位值的无冲突散列。

    结论:如果大多数输入字符串的元素少于 17 个,我更喜欢这个而不是哈希。

    【讨论】:

    • 确实可能存在冲突......映射的问题是我可能在序列中有 30 个字符串。所以我需要 450 位。我只有 256 个……而且我可能有更长的字符串。唯一的好处是我没有使用整个价值空间。此外,如果碰撞风险很小,我可以生成一组位来区分 2 个值并连接到第一个计算值。 (例如,我首先生成类似 123123...001 的内容,下一个与开头匹配的内容将是 123123...002 我仍然需要找到一个“好的”函数来使用...
    • 是的,如果输出位数较少,一些冲突是不可避免的。使用通用哈希函数,冲突是“随机的”并且是均匀分布的。使用专用的哈希函数,您可以控制哪些输入值发生冲突,如果这对您的应用程序有利的话。
    • 我不明白为什么常量位应该添加到冲突中。
    • @NikolaiRuhe 哈希必须平等对待所有位。如果有更多位,就有更多可能的输入值,因此必须将更多输入值映射到相同数量的输出值。 (当然我可能是错的,但这对我来说似乎是合乎逻辑的。)
    • @alain 这很矛盾:如果位是恒定的,那么可能的输入值的数量显然不会改变。
    猜你喜欢
    • 2011-03-31
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    • 2021-11-04
    • 1970-01-01
    • 1970-01-01
    • 2020-01-07
    • 2020-05-24
    相关资源
    最近更新 更多