hash模板

来源:互联网 发布:大数据的前沿技术培训 编辑:程序博客网 时间:2024/06/01 17:22

一维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;}
原创粉丝点击