//将每个单词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