POJ 2774 HDU 4821 -- Hash算法

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章