1. 程式人生 > 實用技巧 >[模板]字串雜湊

[模板]字串雜湊

字串雜湊:

...

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; }