字符串哈希题目总结

来源:互联网 发布:mysql返回上一级 编辑:程序博客网 时间:2024/05/22 02:35

HDU1880

给出对应的字符串,需要建立相应的双向映射。也就是输入first串可以得出对应的second串,输入second串可以得出对应的first串

数据有100000 ,用map<string,string>模拟爆内存。

使用 BKDRHash 哈希函数进行哈希

// BKDR Hash Functionunsigned int BKDRHash(char *str){    unsigned int seed = 131; // 31 131 1313 13131 131313 etc..    unsigned int hash = 0;     while (*str)    {        hash = hash * seed + (*str++);    }     return (hash & 0x7FFFFFFF);}
代码

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int N = 100010;const int H = 100007;struct node{    char que[25];    char ans[85];    int next;};node nodeA[N], nodeB[N];int curA,curB;int hashTableA[N] , hashTableB[N];void initHash(){    for(int i=0;i<H;i++){        hashTableA[i] = -1;        hashTableB[i] = -1;    }    curA = 0;    curB = 0;}unsigned int getHash(char *s){    unsigned int seed = 131;    unsigned int hash = 0;    while(*s){        hash = hash * seed + *s++;    }    return (hash & 0x7fffffff) % H;}void insertHash(char *que,char *ans){    unsigned int h;    h = getHash(que);    strcpy(nodeA[curA].que, que);    strcpy(nodeA[curA].ans, ans);    nodeA[curA].next = hashTableA[h];    hashTableA[h] = curA;    ++curA;    h = getHash(ans);    strcpy(nodeB[curB].que,que);    strcpy(nodeB[curB].ans,ans);    nodeB[curB].next = hashTableB[h];    hashTableB[h] = curB;    ++curB;}int searchHashA(char *que){    unsigned int h = getHash(que);    int next = hashTableA[h];    while(next != -1){        if(strcmp(que,nodeA[next].que) == 0) return next;        next = nodeA[next].next;    }    return -1;}int searchHashB(char *ans){    unsigned int h = getHash(ans);    int next = hashTableB[h];    while(next != -1){        if(strcmp(ans, nodeB[next].ans) == 0) return next;        next = nodeB[next].next;    }    return -1;}int main(){    char str[120], que[25], ans[85],qlen ,alen;    int n,res;    initHash();    while(gets(str)){        if(str[0] == '@') break;        qlen = 0;        for(int i=1;str[i] != ']';++i){            que[qlen++] = str[i];        }        que[qlen] = 0;        alen = 0;        for(int i=qlen+3; str[i] != 0; ++i){            ans[alen++] = str[i];        }        ans[alen] = 0;        insertHash(que,ans);    }    scanf("%d",&n);    getchar();    while(n--){        gets(str);        if(str[0] == '['){            qlen = strlen(str);            str[qlen - 1] = 0;            res = searchHashA(str + 1);            if(res == -1) printf("what?\n");            else printf("%s\n",nodeA[res].ans);        }else{            alen = strlen(str);            res = searchHashB(str);            if(res == -1) printf("what?\n");            else printf("%s\n",nodeB[res].que);        }    }    return 0;}


POJ1743

意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件:

    1.长度至少为5个音符。

    2.在乐曲中重复出现。(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值)

    3.重复出现的同一主题不能有公共部分。

重复2次以上,不能有公共部分的最长子串。

后缀数组可解,

这里用到88进制取模进行哈希函数

想出这种方法的作者连接 http://blog.renren.com/share/283538506/12293487302/0


#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <cstdlib>using namespace std;const int maxh = 10007;const int maxn  =  20010;typedef long long ll;typedef unsigned long long ull;#define mem(a,x) memset(a,x,sizeof a)struct HASHMAP{    int head[maxh] , next[maxn] , size;    ull  state[maxn];    int f[maxn];    void init(){        size = 0;        mem(head,-1);    }    int insert(ull val,int id){        int h = val % maxh;        for(int i=head[h]; i != -1; i = next[i]){            if(val == state[i]) return f[i];        }        f[size] = id;        state[size] = val;        next[size] = head[h];        head[h] = size++;        return f[size  - 1];    }};HASHMAP H;const int SEED = 13331;ull P[maxn];ull S[maxn];int A[maxn];int n;bool check(int x){    H.init();    for(int i=x;i<n;i++)        if(H.insert(S[i] - S[i-x]*P[x],i ) < i - x)            return true;    return false;}int main(){    P[0] = 1;    for(int i=1;i<maxn;i++)        P[i] = P[i-1] * SEED; // unsigned long long 自动取模    while(scanf("%d",&n) && n){        for(int i=1;i<=n;i++)            scanf("%d",&A[i]);        for(int i=1;i<n;i++)            A[i] = A[i + 1] - A[i];        S[0] = 0;        for(int i=1;i<n;i++)            S[i] = S[i-1] * SEED + A[i];        int ans = 0;        int l = 4, r = n - 1;        while(l <= r){            int mid = (l + r) >>1;            if(check(mid)){                ans = mid;                l = mid +1;            }else                r = mid -1;        }        if(ans < 4) ans = -1;        ans++;        printf("%d\n",ans);    }    return 0;}



SCU4438 字符串hash ,好题

通过构造hash表,记录模式串的hash值,然后对主串按顺序遍历每个字符,并存入数组stack,并算出当前串的hash值,通过hash[i] - hash[i - len]*hashpow 算出当前子串是否与模式串hash值相等,相等就将数组stack中的下标回退len长度,实现删除匹配的串。

细节还有待推敲

代码

#include<cstdio>#include<algorithm>#include<map>#include<cstring>#include<vector>#include<queue>#include<set>#include<map>#include<cstdlib>#include<iostream>using namespace std;#define maxn 5000006typedef unsigned long long ll;ll hash = 100007;ll hash_w;ll hash_p [maxn];ll hash_pow[maxn];char p[maxn], w[maxn];char stack[maxn];int len ;void init(){    hash_pow[0] = 1;    for(int i=1;i<maxn;i++)        hash_pow[i] = hash_pow[i -1] *hash;}bool check(int pos){    if(pos >= len && hash_p[pos] -        hash_p[pos - len] *hash_pow[len] == hash_w ){       // cout<<pos<<" "<<hash_p[pos] <<" "<<hash_p[pos - len] *hash_pow[len]<<endl;        return true;    }    return false;}int main(){    init();    while(~scanf("%s%s",w,p)){        len = strlen(w);        //模式串的hash值        hash_w = 0;        for(int i=0;*(w + i);i++){            hash_w = hash_w * hash + *(w + i);           // cout<<hash_w<<"  xx  ";        }      //  cout<<endl;        int top = 0;        for(int i=0; *(p + i); i++){            stack[top++] = *(p + i);            hash_p[top] = hash_p[top - 1]*hash + *(p + i);            if(check(top)) top -= len;        }        for(int i=0;i<top;i++)            printf("%c",stack[i]);        puts("");    }    return 0;}


HDU1280整数hash 水题

#include<cstdio>#include<algorithm>#include<map>#include<cstring>#include<vector>#include<queue>#include<set>#include<map>#include<cstdlib>#include<iostream>using namespace std;#define maxn 5000006typedef unsigned long long ll;#define mem(a,x) memset(a,x,sizeof a)int arr[3333];int vis[10010];int main(){    int n,m;    while(scanf("%d%d",&n,&m) != EOF){        mem(vis,0);        for(int i=0;i<n;i++){            scanf("%d",&arr[i]);        }        for(int i=0;i<n;i++){            for(int j=i+1;j<n;j++){                vis[arr[i] + arr[j] ]  ++;            }        }        bool isfirst = true;        for(int i=10000;i>=0;i--){                if(!m)break;                while(m && vis[i]){                    if(isfirst)                        printf("%d",i);                    else                        printf(" %d",i);                    isfirst = false;                    m--;                    vis[i]--;                }        }        puts("");    }    return 0;}

HDU1496

a*x1^2+b*x2^2+c*x3^2+d*x4^2=0

给出这样一个式子,给出a,b,c,d.求有多少解, abcd范围 [-50,50] x1 - x4 [-100,100];

hash,四层循环改成二层循环,通过数组映射判断是否冲突,冲突就说明匹配,说明有解。另外特殊情况该优化的还要优化,否者会超时。

#include<cstdio>#include<algorithm>#include<map>#include<cstring>#include<vector>#include<queue>#include<set>#include<map>#include<cstdlib>#include<iostream>using namespace std;typedef unsigned long long ll;#define mem(a,x) memset(a,x,sizeof a)//-50*(10000) *2 = 1e 6;const int maxn = 1e6 + 2;int vis[2000010]; //2e6 + 10;int main(){    int a,b,c,d;    while(scanf("%d%d%d%d", &a,&b,&c,&d) != EOF){        if(a > 0 && b> 0 && c > 0 && d > 0){//没有这句就超市了            puts("0");            continue;        }        mem(vis,0);        for(int i=1;i<=100;i++){            for(int j=1;j<=100;j++){                vis[a*i*i + b*j*j + maxn ] ++;            }        }        int ans = 0;        for(int i=1;i<=100;i++){            for(int j=1;j<=100;j++){                ans += vis[-(c*i*i + d*j*j)+maxn];            }        }        // 每个i ,j都是可正 可负,2 * 2 * 2 * 2 == 16        printf("%d\n",ans*16);    }    return 0;}

ACDREAM 1726

给出N个数 和一个数 H ,从N个数中选择任意多个数,问有多少种选择使得选的数的和 等于H 。

N <=40 H <= 1e9

1e9需要哈希一下。

N = 40 折半之后哈希就可以了。

二分数据,数据减半后,时间复杂度 有 2 ^ 40 变为 2 ^ 20;

再用HASH判断是否满足

#include<cstdio>#include<algorithm>#include<map>#include<cstring>#include<vector>#include<queue>#include<set>#include<map>#include<cstdlib>#include<iostream>using namespace std;typedef long long ll;#define mem(a,x) memset(a,x,sizeof a)const int maxn = 1<<20; // 1048576const int hash = 1000007; //开多大的hash/*3 1000010next记录的是之前的headhead代表着数据在a数组中的位置。head始终代表着头结点*/struct hashmap{    ll a[maxn]; //映射入的数组    int head[hash] , next[maxn],size;    void init(){        mem(head,-1);        size = 0;    }    /*    取模相同的数,存入a中之后,可以通过next遍历找到head进而找到对应a[i];    实现了取模相同的数放到邻接表里一样的查询。    */    bool find(ll val){ //查找一个元素是否在hash表中        int tmp = (val % hash + hash) % hash;        for(int i=head[tmp]; i != -1;i = next[i]){            if(val == a[i]) return true;        }        return false;    }    void add(ll val){ // 添加元素到hash表        int tmp = (val % hash + hash) %hash;        if(find(val)) return ;        a[size] = val;        next[size] = head[tmp];        head[tmp] = size ++;    }}h1;int n,m,num[55];int main(){////    h1.init();//    h1.add(3);//    h1.add(4);//    h1.add(5);//    h1.add(6);//    h1.add(1000010);//    h1.add(2000017);    while(~scanf("%d%d",&n,&m)){        h1.init();        for(int i=0;i<n;i++) scanf("%d",num+i);        int t = n/2;        // 将t种取或者不取 映射为二进制数,进行枚举        for(int i=0;i<(1<<t);i++){            ll sum = 0;            for(int j=0;j < t;j++){                if(i & (1<<j)){                    sum += num[j]; //加上选中的数                }            }            if(sum > m) continue;            h1.add(sum);        }        int tt = n - t; //枚举剩下的数        int flag = 0;        for(int i=0;i<(1<<tt);i++){            ll sum = 0;            for(int j=0;j<tt;j++){                if(i & (1<<j))                    sum += num[t + j]; //加上剩下的数中符合条件的            }            if(sum > m) continue;            if(h1.find(m - sum)){                flag = 1; break;            }        }        if(flag)            printf("Yes\n");        else            printf("No\n");    }    return 0;}


0 0
原创粉丝点击