非空字符串的哈希码可以为零吗?
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
以及firstParts
和lastParts
的大英文单词列表,我们可以找到众所周知的pollinating sandboxes
以及revolvingly admissable
、laccaic dephase
、toxity fizzes
等。
请注意,如果您为 findStrings
和 firstParts
和 lastParts
提供一个大小为 N 的大型列表,并为 midParts
提供一个简短的固定列表,它在 O 中运行(N) 时间。
【讨论】:
以上是关于非空字符串的哈希码可以为零吗?的主要内容,如果未能解决你的问题,请参考以下文章