[英]Search for a substring in an another string using hashing
我編寫了代碼以使用散列在另一個字符串中查找子字符串,但它給了我錯誤的結果。
代碼工作原理的描述:
p=31
的前n
冪存儲在數組pows
。s[0..i]
哈希值存儲在數組h
。h
數組計算每個長度為 9 的子串的哈希值並將其存儲在一個集合中。t
並存儲其散列值。t
哈希值和集合中的哈希值。 散列h[n2-1]
應該存在於集合中,但它不存在。 你能幫我找出代碼中的錯誤嗎?
注意:當我使用模逆而不是乘以pows[i-8]
,代碼運行良好。
#include <bits/stdc++.h>
#define m 1000000007
#define N (int)2e6 + 3
using namespace std;
long long pows[N], h[N], h2[N];
set<int> ss;
int main() {
string s = "www.cplusplus.com/forum";
// powers array
pows[0] = 1;
int n = s.length(), p = 31;
for (int i = 1; i < n; i++) {
pows[i] = pows[i - 1] * p;
pows[i] %= m;
}
// hash from 0 to i array
h[0] = s[0] - 'a' + 1;
for (int i = 1; i < n; i++) {
h[i] = h[i - 1] + (s[i] - 'a' + 1) * pows[i];
h[i] %= m;
}
// storing each hash with 9 characters in a set
ss.insert(h[8]);
for (int i = 9; i < n; i++) {
int tp = h[i] - h[i - 9] * pows[i - 8];
tp %= m;
tp += m;
tp %= m;
ss.insert(tp);
}
// print hashes with 9 characters
set<int>::iterator itr = ss.begin();
while (itr != ss.end()) {
cout << *(itr++) << " ";
}
cout << endl;
// t is the string that i want to check if it is exist in s
string t = "cplusplus";
int n2 = t.length();
h2[0] = t[0] - 'a' + 1;
for (int i = 1; i < n2; i++) {
h2[i] = h2[i - 1] + (t[i] - 'a' + 1) * pows[i];
h2[i] %= m;
}
// print t hash
cout << h2[n2 - 1] << endl;
return 0;
}
我可以看到您的代碼有兩個問題:
long long
)存儲在一個int
變量中。 這可能會導致整數溢出,並且您計算的哈希值可能不正確。s = {s[0], s[1], ..., s[n-1]}
,計算哈希的方法是: h = ∑ s[i] * p^i
。 在這種情況下,給定存儲在h
的前綴哈希,子串s[l..r]
(包括)的哈希應該是(h[r] - h[l - 1]) / p^(r-l+1)
, 而不是你寫的。 這也是為什么使用模逆(需要在模下執行除法)是正確的。 我認為計算散列的更常見方法是相反的方法,即h = ∑ s[i] * p^(ni-1)
。 這允許您將子串哈希計算為h[r] - h[l - 1] * p^(r-l+1)
,這不需要計算模逆。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.