hash模板

一維hash

//求原串中有多少個模式串
//Seed[i]是seed的i次冪
//hash[j]-hash[i-1] * Seed[len]是區間[i,j]的hash值,len是區間長度
typedef long long ll;
typedef unsigned long long ull;
const int N = 1000000 + 10, M = 10000 + 10, INF = 0x3f3f3f3f;
const int seed = 31;//31,131,1313,13131,131313...
char pat[M], ori[N];
ull Seed[N], hash_ori[N];
ull BKDRhash(char *str)
{
    ull h = 0;
    for(int i = 0; str[i]; i++)
        h = h * seed + str[i];
    return h;
}
int main()
{
    Seed[0] = 1;
    for(int i = 1; i < N; i++) Seed[i] = Seed[i-1] * seed;
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%s%s", pat+1, ori+1);
        ull hash_pat = BKDRhash(pat+1);
        int len_pat = strlen(pat+1);
        hash_ori[0] = 0;
        int ans = 0;
        for(int i = 1; ori[i]; i++)
        {
            hash_ori[i] = hash_ori[i-1] * seed + ori[i];//也是BKDRhash
            int j = i - len_pat + 1;
            if(j >= 1)
            {hash_ori[i] - hash_ori[j-1] * Seed[len_pat]是區間[j,i]的hash值,len_pat是區間長度
                if(hash_ori[i] - hash_ori[j-1]*Seed[len_pat] == hash_pat) ans++;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

二維hash:

//給定一個n*m的字符矩陣,找到兩個內容一樣的正方形,輸出這個正方形的最大邊長
//二維hash,先對每一行hash一次,然後在此基礎上對每一列hash一次
typedef unsigned long long ull;
const int N = 500 + 10, INF = 0x3f3f3f3f;
const int seed = 131, Seed = 1789;
char ori[N][N];
ull hash1[N][N], seed_pow[N];
ull hash2[N][N], Seed_pow[N];
ull a[N*N];
int n, m;
bool check(int k)
{
    int tot = 0;
    for(int i = k; i <= n; i++)
    {
        for(int j = k; j <= m; j++)
        {
            ull tmp = hash2[i][j] - hash2[i-k][j] * Seed_pow[k] - hash2[i][j-k] * seed_pow[k] + hash2[i-k][j-k] * Seed_pow[k] * seed_pow[k];
            //ull tmp = hash2[i][j] - hash2[i-k][j] * Seed_pow[k] - (hash2[i][j-k] - hash2[i-k][j-k] * Seed_pow[k]) * seed_pow[k];
            a[++tot] = tmp;
        }
    }
    sort(a + 1, a + 1 + tot);
    for(int i = 1; i <= tot-1; i++)
        if(a[i] == a[i+1]) return true;
    return false;
}
int main()
{
    seed_pow[0] = Seed_pow[0] = 1;
    for(int i = 1; i < N; i++)
    {
        seed_pow[i] = seed_pow[i-1] * seed;
        Seed_pow[i] = Seed_pow[i-1] * Seed;
    }
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf(" %s", ori[i] + 1);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            hash1[i][j] = hash1[i][j-1] * seed + ori[i][j];
    for(int i = 1; i <= m; i++)
        for(int j = 1; j <= n; j++)
            hash2[j][i] = hash2[j-1][i] * Seed + hash1[j][i];
    int ans = 0;
    int l = 0, r = min(n, m);
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(check(mid)) ans = mid, l = mid + 1;
        else r = mid - 1;
    }
    printf("%d\n", ans);
    return 0;
}

ELFhash:

給出一些數字,求出這些數字中出現次數,輸出最多的那個次數。其中數字不超過30#include <bits/stdc++.h>
using namespace std;

typedef unsigned int ui;
const int N = 7003, MOD = 7003;
int Hash[N], num[N];
int res;
int ELFhash(char *str)//思想就是一直雜糅,使字符之間互相影響
{
    ui h = 0, g;
    while(*str)
    {
        h = (h<<4) + *str++; //h左移4位,當前字符佔8位,加到h中進行雜糅
        if((g = h & 0xf0000000) != 0) //取h最左四位的值,若均爲0,則括號中執行與否沒區別,故不執行
        {
            h ^= g>>24; //用h的最左四位的值對h的右起5~8進行雜糅
            h &= ~g;//清空h的最左四位
        }
    }
    return h; //因爲每次都清空了最左四位,最後結果最多也就是28位二進制整數,不會超int
}
void hash_table(char *str)
{
    int k = ELFhash(str);
    int t = k % MOD;
    while(Hash[t] != k && Hash[t] != -1) t = (t + 1) % MOD;//開放地址法處理hash
    if(Hash[t] == -1) num[t] = 1, Hash[t] = k;
    else res = max(res, ++num[t]);
}
int main()
{
    int n;
    char str[100];
    while(~ scanf("%d", &n))
    {
        getchar();
        res = 1;
        memset(Hash, -1, sizeof Hash);
        for(int i = 1; i <= n; i++)
        {
            scanf("%s", str);
            int j = 0;
            while(str[j] == '0') j++;
            hash_table(str + j);
        }
        printf("%d\n", res);
    }
    return 0;
}
發佈了601 篇原創文章 · 獲贊 25 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章