如何创建匹配任何字符串排列的唯一哈希

时间:2016-08-12 18:30:05

标签: algorithm hash

给定一个字符串abcd如何创建一个唯一的散列方法,该方法将对这4个字符进行散列以匹配bcad或字母abcd的任何其他排列?

目前我有这段代码

long hashString(string a) {
    long hashed = 0;
    for(int i = 0; i < a.length(); i++) { 
        hashed += a[i] * 7; // Timed by a prime to make the hash more unique?
    } 
    return hashed;
}

现在这不起作用因为ad将与bc一起使用。

我知道你可以通过将字母的位置乘以字母本身hashed += a[i] * i来使其更独特,但是字符串不会哈希到它的排列。

是否可以创建实现此目的的哈希?

修改

有些人建议在对字符串进行哈希处理之前对其进行排序。这是一个有效的答案,但排序将花费O(nlog)时间,我正在寻找一个在O(n)时间运行的哈希函数。

我希望在O(1)记忆中做到这一点。

5 个答案:

答案 0 :(得分:4)

您可以做的基本事情是在应用哈希函数之前对字符串进行排序。因此,要计算“adbc”或“dcba”的哈希值,您需要计算“abcd”的哈希值。

如果要确保散列函数中没有冲突,那么唯一的方法是将散列结果作为字符串。存在比32位(或64位)整数更多的字符串,因此冲突是不可避免的(尽管有良好的散列函数,但不太可能发生冲突)。

答案 1 :(得分:3)

最简单的理解方法:对字符串中的字母进行排序,然后对生成的字符串进行散列。

您原始想法的一些变体也有效,例如:

long hashString(string a) {
    long hashed = 0;
    for(int i = 0; i < a.length(); i++) {
        long t = a[i] * 16777619;
        hashed += t^(t>>8);
    } 
    return hashed;
}

答案 2 :(得分:2)

我想你需要一个散列,这样两个字谜就会散列到相同的值。我建议你先排序它们并使用任何常见的哈希函数,如md5。我使用Scala编写以下代码:

 import java.security.MessageDigest

 def hash(s: String) = {
    MessageDigest.getInstance("MD5").digest(s.sorted.getBytes)
 }

在scala中注意:

 scala> "hello".sorted
 res0: String = ehllo

 scala> "cinema".sorted
 res1: String = aceimn 

答案 3 :(得分:2)

创建一个包含26个整数的数组,对应于字母a-z。将其初始化为0.从头到尾扫描字符串,并递增与当前字母对应的数组元素。请注意,到目前为止,算法具有O(n)时间复杂度和O(1)空间复杂度(因为数组大小是常量)。

最后,使用您喜欢的哈希函数散列数组的内容。

答案 4 :(得分:2)

概要:在哈希值中存储字母的直方图。

步骤1:计算字母的直方图(因为直方图唯一地标识字符串中的字母而不考虑字母的顺序)。

int histogram[26];
for ( int i = 0; i < a.length(); i++ )
    histogram[a[i] - 'a']++;

步骤2:将直方图打包到哈希值中。你有几个选择。选择哪个选项取决于您可以对字符串施加什么样的限制。

如果您知道每个字母的出现次数不会超过3次,那么表示计数需要2位,因此您可以创建一个保证唯一的52位散列。

如果您愿意使用128位散列,则24个字母有5位,2个字母有4位(例如qz)。 128位哈希允许每个字母出现31次(qz的15次)。

但是如果你想要一个固定大小的散列,比如说16位,那么你需要以减少冲突的方式将直方图打包成这16位。最简单的方法是创建一个26字节的消息(直方图中每个条目一个字节,允许每个字母最多出现255次)。然后使用您最喜欢的CRC生成器获取消息的16位CRC。