【C】字符串哈希

//将每个单词hash
//先初始化powp数组:powp[0]=1,powp[i]=powp[i-1]*P%mod
//再求解每个h,h[0]=str[0],h[i]=(h[i-1]*p+str[i])%mod
//最后找出各个单词的首尾,求解h[i…j]:
//if i==1,h[i…j]=h[j]
//else h[i…j]=((h[j]-h[i-1]*powp[j-i+1])%mod+mod)%mod

1.求解最长公共字串长度

#include<stdio.h>
#include<iostream>
#include<vector>
#include<string>
#include<sstream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int P=10000019;
const int MOD=1000000007;
const int maxx=100001;
LL powP[maxx];
LL h1[maxx]={0},h2[maxx]={0};
vector<pair<int,int> > pr1,pr2;//子串hash值及子串长度
void init(int len){
    powP[0]=1;
    for(int i=1;i<=len;i++){
        powP[i]=powP[i-1]*P%MOD;
    }
}

void calH(LL h[],string &str){
    h[0]=str[0];
    for(int i=1;i<str.size();i++){
        h[i]=(h[i-1]*P+str[i])%MOD;
    }
}
//计算h[i...j]的hash
LL calsubH(LL h[],int i,int j){
    if(i==0) return h[j];
    return ((h[j]-h[i-1]*powP[j-i+1])%MOD+MOD)%MOD;
}
//将所有子串hash及长度存入vector
void calsubHin(LL h[],int len,vector<pair<int,int> > &pr){
    for(int i=0;i<len;i++){
        for(int j=i;j<len;j++){
            int hashv=calsubH(h,i,j);
            pr.push_back(make_pair(hashv,j-i+1));
        }
    }
}
//计算子串hash中的相同值,并取最大
int getmax(){
    int ans=0;
    for(int i=0;i<pr1.size();i++){
        for(int j=0;j<pr2.size();j++){
            if(pr1[i].first==pr2[j].first){
                ans=max(pr1[i].second,ans);
            }
        }
    }
    return ans;
}
int main(){
    string str1,str2;
    getline(cin,str1);
    getline(cin,str2);
    init(max(str1.size(),str2.size()));
    calH(h1,str1);
    calH(h2,str2);
    calsubHin(h1,str1.size(),pr1);
    calsubHin(h2,str2.size(),pr2);
    cout<<getmax();
    return 0;
}

2.输出最长公共字串

#include<stdio.h>
#include<iostream>
#include<vector>
#include<string>
#include<sstream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int P=10000019;
const int MOD=1000000007;
const int maxx=100001;
LL powP[maxx];
LL h1[maxx]={0},h2[maxx]={0};
struct HASH{
    LL data;
    int start,end,len;
};
vector<HASH> pr1,pr2;
void init(int len){
    powP[0]=1;
    for(int i=1;i<=len;i++){
        powP[i]=powP[i-1]*P%MOD;
    }
}
void calH(LL h[],string &str){
    h[0]=str[0];
    for(int i=1;i<str.size();i++){
        h[i]=(h[i-1]*P+str[i])%MOD;
    }
}
//计算h[i...j]的hash
LL calsubH(LL h[],int i,int j){
    if(i==0) return h[j];
    return ((h[j]-h[i-1]*powP[j-i+1])%MOD+MOD)%MOD;
}
//将所有子串hash存入vector
void calsubHin(LL h[],int len,vector<HASH> &pr){
    for(int i=0;i<len;i++){
        for(int j=i;j<len;j++){
            HASH hash;
            int hashv=calsubH(h,i,j);
            hash.data=hashv;
            hash.start=i;hash.end=j;hash.len=j-i+1;
            pr.push_back(hash);
        }
    }
}
//计算子串hash中的相同值,并取最大长度
int getmax(int &s,int &e){
    int ans=0;
    for(int i=0;i<pr1.size();i++){
        for(int j=0;j<pr2.size();j++){
            if(pr1[i].data==pr2[j].data){
                //printf("i=%d,j=%d\n",i,j);
                //printf("pr1:%d-%d,pr2:%d-%d\n",pr1[i].start,pr1[i].end,pr2[j].start,pr2[j].end);
                if(ans<pr1[i].len){
                    s=min(pr1[i].start,pr2[j].start);
                    e=min(pr1[i].end,pr2[j].end);
                    ans=pr1[i].len;
                    //printf("1.s=%d,e=%d\n",s,e);
                }
                else if(ans==pr1[i].len){
                    if(s>min(pr1[i].start,pr2[j].start)){//s比当前后出现
                        s=min(pr1[i].start,pr2[j].start);
                        e=min(pr1[i].end,pr2[j].end);
                        //printf("2.s=%d,e=%d\n",s,e);
                    }
                }
            }
        }
    }
    return ans;
}
int main(){
    string str1,str2;
    getline(cin,str1);
    getline(cin,str2);
    init(max(str1.size(),str2.size()));
    calH(h1,str1);
    calH(h2,str2);
    calsubHin(h1,str1.size(),pr1);
    calsubHin(h2,str2.size(),pr2);
    int s=0,e=0;
    getmax(s,e);
    for(int i=s;i<=e;i++){
        cout<<str1[i];
    }
    return 0;
}

7-43 字符串关键字的散列映射(25 分)
给定一系列由大写英文字母组成的字符串关键字和素数P,用移位法定义的散列函数H(Key)将关键字Key中的最后3个字符映射为整数,每个字符占5位;再用除留余数法将整数映射到长度为P的散列表中。例如将字符串AZDEG插入长度为1009的散列表中,我们首先将26个大写英文字母顺序映射到整数0~25;再通过移位将其映射为3×32
​2
​​+4×32+6=3206;然后根据表长得到,即是该字符串的散列映射位置。
发生冲突时请用平方探测法解决。
输入格式:
输入第一行首先给出两个正整数N(≤500)和P(≥2N的最小素数),分别为待插入的关键字总数、以及散列表的长度。第二行给出N个字符串关键字,每个长度不超过8位,其间以空格分隔。
输出格式:
在一行内输出每个字符串关键字在散列表中的位置。数字间以空格分隔,但行末尾不得有多余空格。
输入样例1:
4 11
HELLO ANNK ZOE LOLI
输出样例1:
3 10 4 0
输入样例2:
6 11
LLO ANNA NNK ZOJ INNK AAA
输出样例2:
3 0 10 9 6 1

#include<stdio.h>
#include<iostream>
#include<vector>
#include<string>
#include<math.h>
#include<map>
using namespace std;
int h[2000]={0};//p:>1000的最小素数
vector<int> pos;
map<string,int> mp;
int n,p;
int deal(string str){
    int len=str.size();
    int a=0;
    if(len-3>=0){//长度大于等于三
        for(int i=len-3;i<len;i++){
            a+=(int)(str[i]-'A')*(int)pow(32.0,(double)len-i-1);
        }
    }
    else if(len-2>=0){
        for(int i=len-2;i<len;i++){
            a+=(int)(str[i]-'A')*(int)pow(32.0,(double)len-i-1);
        }
    }
    else if(len-1>=0){
        for(int i=len-1;i<len;i++){
            a+=(int)(str[i]-'A')*(int)pow(32.0,(double)len-i-1);
        }
    }
    return a%p;//首次hash的位置
}
int tance(int a){
    if(h[a]==0) return a;
    int i=1;
    while(h[a]!=0&&i<=p/2){
        int b=a;
        a=(b+i*i)%p;
        if(h[a]==0) return a;
        a=(b-i*i+p)%p;//以免减成负数
        if(h[a]==0) return a;
        i++;
        a=b;
    }
    return a;
}
int main(){
    cin>>n>>p;
    getchar();
    for(int i=0;i<n;i++){
        string str;
        cin>>str;
        if(mp.find(str)!=mp.end()){//曾经对应过
            int last=mp.find(str)->second;
            pos.push_back(last);
        }
        else{
            int first=deal(str);
            int last=tance(first);
            h[last]=1;
            pos.push_back(last);
            mp[str]=last;
        }
    }
    for(int i=0;i<pos.size();i++){
        if(i!=0) cout<<" "<<pos[i];
        else cout<<pos[i];
    }
    return 0;
}
//如果字符串完全相同--不止后三个,则输出原来的hash位置
//需要把已经对应好的字符串及其hash值存入map

猜你喜欢

转载自blog.csdn.net/li_jiaqian/article/details/79514257