[模板]字串雜湊
阿新 • • 發佈:2021-01-07
字串雜湊:
... char s[1000]; unsigned long long hs[1000], p[1000]; // 注意是unsigned long long, 這兩個陣列與字串大小相同 int main() { scanf("%s", s + 1); p[0] = 1; int len = strlen(s + 1); for (int i = 1; i <= len; i++) { hs[i] = hs[i - 1] * 131 + s[i] - 'a' + 1; // hs[i] 即為字串s在1~i部分的子串的雜湊值 p[i] = p[i - 1] * 131; // p[i] 表示131^i } /* 表示l到r的雜湊值: hs[r] - hs[l - 1] * p[r - l + 1]; 若兩段字串的雜湊值相等,則視其為相同字串.這使得比較兩端字串的複雜度為O(1) */ return 0; }
一般來說,我們取p=131或p=13331,此時Hash產生衝突的概率極低,...
除了極特殊構造的資料上,上述Hash演算法很難產生衝突,一般情況下上述Hash演算法完全可以出現在題目的標準解答中.
----<<指南>>
重複部分只會出現在一個字串的字尾和另一個字串的前綴出現,那麼只需要以O(n)列舉重複部分長度即可.注意有兩種情況要考慮.
理論上說,用strcmp可以達到與比較雜湊值相同的效果,只是前者要處理一些細節,並且複雜度最壞情況下達到了O(n).
這題的資料範圍非常小.我在更新ans時使用了沒必要出現的奇怪技巧.
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> using namespace std; int l1, l2, ans;char s1[100], s2[100]; unsigned long long hs1[100], hs2[100], p[100]; int main() { scanf("%s%s", s1 + 1, s2 + 1); l1 = strlen(s1 + 1), l2 = strlen(s2 + 1); p[0] = 1; for (int i = 1; i <= max(l1, l2); i++) { hs1[i] = hs1[i - 1] * 131 + s1[i] - 'a' + 1; hs2[i] = hs2[i - 1] * 131 + s2[i] - 'a' + 1; p[i] = 131 * p[i - 1]; } for (int i = 1; i <= l1; i++) if (hs1[l1] - hs1[l1 - i] * p[i] == hs2[i]) ans = i; for (int i = ans; i <= l2; i++) if (hs2[l2] - hs2[l2 - i] * p[i] == hs1[i]) ans = i; printf("%d\n", ans); return 0; }