Hash的用處就是將一個字符串從頭到尾的特殊化記錄一下,每次要判斷字符串是否相等,直接看Hash值是否相等就好了
這裏用的均爲BKDR-Hash
POJ 2774
題目鏈接:http://poj.org/problem?id=2774
題目大意:給你兩個字符串,求它們的最長公共子串的長度
思路:對兩個字符串都Hash掃一下, 通過二分來判定公共子串長度,先求s1中長度爲t的子串的Hash值,再求s2中的,對比是否相等
AC代碼:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn = 100005;
char s1[maxn], s2[maxn];
ull hash1[maxn], hash2[maxn], a[maxn], pows[maxn];
int len1, len2;
inline ull getHash(ull h[], int i, int j){ //計算[i, j)子串的hash值
return h[j] - h[i] * pows[j-i];
}
bool solve(int t) //判斷是否有長度爲t的解
{
int n = 0;
for(int i = t; i <= len1; i++){
a[n++] = getHash(hash1, i-t, i); //計算s1的每一個長度爲t的子串的hash值
}
sort(a, a+n);
for(int i = t; i <= len2; i++){
ull h = getHash(hash2, i-t, i); //計算s2的每一個長度爲t的子串的hash值
if(binary_search(a, a+n, h)) return true; //查找s1中是否有子串hash值與其相等
}
return false;
}
int main()
{
cin >> s1 >> s2;
len1 = strlen(s1), len2 = strlen(s2);
int l = 0, r = max(len1, len2);
pows[0] = 1;
for(int i = 1; i <= r; i++){
pows[i] = pows[i-1]*131; //預處理冪次
}
hash1[0] = 0;
for(int i = 0; i < len1; i++){
hash1[i+1] = hash1[i]*131 + s1[i]; // 預處理s1的前綴hash值
}
for(int i = 0; i < len2; i++){
hash2[i+1] = hash2[i]*131 + s2[i];
}
while(l != r){
int t = (l+r) >> 1;
if(solve(t+1)) l = t+1;
else r = t;
}
cout << l << '\n';
return 0;
}
HDU 4821
題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4821
題目大意:一個字符串,它的子串有m個長爲l的小子串構成,這些小子串各不相同,問有多少個子串?
思路:Hash之後,從頭掃+移塊掃,對每個長爲m*l的子串內部進行判斷,可以用map來進行存儲每一個小子串的Hash值,方便計數
AC代碼:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn = 1e5+5;
char s[maxn];
ull Hash[maxn], base[maxn];
map<ull, int> p;
int main()
{
int m, l;
while(~scanf("%d %d", &m, &l)){
cin >> s;
int len = strlen(s);
base[0] = 1;
for(int i = 1; i <= len; i++){
base[i] = base[i-1]*131;
}
Hash[0] = 0;
for(int i = 0; i < len; i++){
Hash[i+1] = Hash[i]*131 + s[i];
}
int a = 0;
for(int i = 0; i < l && i+m*l <= len; i++){
p.clear();
for(int j = i; j < m*l+i; j+=l){
p[Hash[j+l] - Hash[j]*base[l]]++;
}
if(p.size() == m) a++;
for(int j = i; j+l <= len-m*l; j+=l){ //移塊掃
p[Hash[j+l] - Hash[j]*base[l]]--;
if(p[Hash[j+l] - Hash[j]*base[l]] == 0) p.erase(Hash[j+l] - Hash[j]*base[l]); // 將原先塊區刪除
p[Hash[j+m*l+l] - Hash[j+m*l]*base[l]]++; // 添加新的塊區
if(p.size() == m) a++;
}
}
cout << a << '\n';
}
return 0;
}