非空字符串的哈希码可以为零吗?

Posted

技术标签:

【中文标题】非空字符串的哈希码可以为零吗?【英文标题】:Can a non-empty string have a hashcode of zero? 【发布时间】:2013-09-15 18:50:17 【问题描述】:

“非空”是指在这个问题中包含至少一个非零字符的字符串。

作为参考,这里是 hashCode 的实现:

1493    public int hashCode() 
1494        int h = hash;
1495        if (h == 0) 
1496            int off = offset;
1497            char val[] = value;
1498            int len = count;
1499
1500            for (int i = 0; i < len; i++) 
1501                h = 31*h + val[off++];
1502            
1503            hash = h;
1504        
1505        return h;
1506    

并且算法在文档中指定。

在整数溢出发生之前,答案很简单:不会。但我想知道的是,由于整数溢出,非空字符串的哈希码是否可能为零?你能建造一个吗?

理想情况下,我正在寻找的是数学演示(或链接)或构造算法。

【问题讨论】:

你说的null hashcode是什么意思?类型是int? 也不确定您指的是什么“长”。 hashCode() 方法处理整数和字符。 我想这是可能的。但是找到一个确切的案例会很头疼。 这个问题怎么可能“太宽泛”了? @JoopEggen 请阅读问题直到第一句... 【参考方案1】:

当然。例如,字符串 f5a5a608 的哈希码为零。

我通过简单的蛮力搜索发现:

public static void main(String[] args)
    long i = 0;
    loop: while(true)
        String s = Long.toHexString(i);
        if(s.hashCode() == 0)
            System.out.println("Found: '"+s+"'");
            break loop;
        
        if(i % 1000000==0)
            System.out.println("checked: "+i);              
        
        i++;
           

编辑: 从事 JVM 工作的 Joseph Darcy 甚至编写了一个程序,该程序可以通过在反向。

【讨论】:

Incentively, my dear, I don't tessellate a derangement. 哈希码为零。他们有很多。这样想,你有大约 2^-64 的机会将字符串散列为零。然后想想有多少个可能的字符串。 @Obicere 我完全不确定溢出是否能够导致零值。 @Obicere:哈希函数不一定会使用所有具有相同可能性(或根本不可能)的哈希值,尽管您当然希望 good 哈希函数。 @MichaelBorgwardt 当然,但字符越多分布越好。当接近无限字符时,它应该接近那个值。此外,由于字符串排列的指数增益,字符越多,1 或 2 字符串对结果的影响就越小。 我认为 unhash 函数不能用于此目的。它只会找到由零个字符组成的字符串。【参考方案2】:

请注意int h;。它可能会溢出,每个满足h % 2^31 == 0 的字符串都可能导致这种情况。

public class HelloWorld 
    public static void main(String []args) 
       System.out.println("\u0001!qbygvW".hashCode());
        System.out.println("9 $Ql(0".hashCode());
        System.out.println(" #t(lrl".hashCode());
        System.out.println(" !!#jbwa".hashCode());
        System.out.println(" !!#jbw|||".hashCode());
        System.out.println(" !!!!Se|aaJ".hashCode());
        System.out.println(" !!!!\"xurlls".hashCode());
    

很多字符串...

【讨论】:

【参考方案3】:

这是查找和打印任何所需 hashCode 值的字符串的代码:

public static int findIntInverse(int x) 
    // find the number y such that as an int (after overflow) x*y = 1
    // assumes x is odd, because without that it isn't possible.
    // works by computing x ** ((2 ** 32) - 1)
    int retval = 1;
    for (int i = 0; i < 31; i++) 
        retval *= retval;
        retval *= x;
    
    return retval;


public static void findStrings(
        int targetHash,
        Iterable<String> firstParts,
        Iterable<String> midParts,
        Iterable<String> lastParts) 
    Map<Integer, String> firstHashes = new HashMap<>();
    for (String firstPart : firstParts) 
        firstHashes.put(firstPart.hashCode(), firstPart);
    
    int maxlastlen = 0;
    int maxmidlen = 0;
    for (String midPart : midParts) 
        maxmidlen = Math.max(midPart.length(), maxmidlen);
    
    for (String lastPart : lastParts) 
        maxlastlen = Math.max(lastPart.length(), maxlastlen);
    
    List<Integer> hashmuls = new ArrayList<>();
    String baseStr = "\u0001";
    for (int i = 0; i <= maxmidlen + maxlastlen; i++) 
        hashmuls.add(baseStr.hashCode());
        baseStr += "\0";
    
    // now change each hashmuls into its negative "reciprocal"
    for (int i = 0; i < hashmuls.size(); i++) 
        hashmuls.set(i, -findIntInverse(hashmuls.get(i)));
    
    for (String lastPart : lastParts) 
        for (String midPart : midParts) 
            String tail = midPart + lastPart;
            Integer target = hashmuls.get(tail.length()) * (tail.hashCode() - targetHash);
            if (firstHashes.containsKey(target)) 
                System.out.print(firstHashes.get(target));
                System.out.println(tail);
            
        
    

通过使用常用英语单词列表作为每个部分的种子,发现了一些有趣的发现:

sand nearby chair
king concentration feeling
childhood dish tight
war defensive to
ear account virus

仅使用Arrays.asList(" ")midParts 以及firstPartslastParts 的大英文单词列表,我们可以找到众所周知的pollinating sandboxes 以及revolvingly admissablelaccaic dephasetoxity fizzes等。

请注意,如果您为 findStringsfirstPartslastParts 提供一个大小为 N 的大型列表,并为 midParts 提供一个简短的固定列表,它在 O 中运行(N) 时间。

【讨论】:

以上是关于非空字符串的哈希码可以为零吗?的主要内容,如果未能解决你的问题,请参考以下文章

用于测试非空字符串和非空字符串的兼容 SQL

Django:查找非空字符串的优雅方式

数据结构之串类型

数据结构-串

字符串模糊匹配

HDU 5782 Cycle(KMP+哈希)