你真的可以通过哈希有效地将相同的字符串分组吗?
Posted
技术标签:
【中文标题】你真的可以通过哈希有效地将相同的字符串分组吗?【英文标题】:Can you really divide identical strings into groups efficiently through hashes? 【发布时间】:2022-01-15 07:32:29 【问题描述】:我正在阅读这篇文章 this article 谈论字符串散列。在 “在字符串数组中搜索重复字符串” 部分,它声称您可以使用字符串散列对时间复杂度为 O(M*N*log(N))
的相同字符串进行分组。
查看文章中介绍的这个代码示例
vector<vector<int>> group_identical_strings(vector<string> const& s)
int n = s.size();
vector<pair<long long, int>> hashes(n);
for (int i = 0; i < n; i++)
hashes[i] = compute_hash(s[i]), i;
sort(hashes.begin(), hashes.end());
vector<vector<int>> groups;
for (int i = 0; i < n; i++)
if (i == 0 || hashes[i].first != hashes[i-1].first)
groups.emplace_back();
groups.back().push_back(hashes[i].second);
return groups;
我对这段代码如何正确感到非常困惑,因为它仅在hashes[i].first != hashes[i-1].first
的条件下创建一个新组。两个字符串可以不同但具有相同的哈希值,因此即使它们不同,两个字符串也可以添加到同一个组中?这个条件在我看来还不够。
我错了吗?这段代码正确吗?为什么?
如果不是,那么这种算法或至少这种复杂性真的可以实现吗?
【问题讨论】:
这与我们说哈希表具有 amortized O(1) 查找的原因相同。当然,自然会发生冲突,我们将不得不依靠其他一些(可能不是 O(1))过程来区分共享哈希的 2+ 个键。然而,从统计上看,这种情况发生的频率应该足够低,每次碰撞的成员也足够少,我们可以说总体上摊销的时间复杂度仍然是 O((1)。 【参考方案1】:您非常正确,两个不同的字符串可以具有相等的哈希值。这称为hash collision。但是,归结为您使用的散列函数。有些哈希函数不太可能找到冲突,因此您可以很好地使用该算法而不必担心它会被破坏。在密码学中,我们依赖于加密安全散列函数的这一特性(参见例如here)。
事实上,您提到的消息来源如下:
这是您必须牢记的重要部分。使用散列不会 100% 确定正确,因为两个完全不同的字符串可能具有相同的散列(散列冲突)。然而,在大多数任务中,这可以安全地忽略,因为两个不同字符串的哈希冲突的概率仍然非常小。我们将在本文中讨论一些如何将碰撞概率保持在非常低的技术。
因此,正如您所说,该算法在数学上并不正确。但是通过正确选择散列函数,它在实践中崩溃的概率可以忽略不计。
【讨论】:
以上是关于你真的可以通过哈希有效地将相同的字符串分组吗?的主要内容,如果未能解决你的问题,请参考以下文章