字符串Hash总结

一.什么是字符串Hash

字符串Hash就是把一个字符串表示为一个unsigned long long 类型的数,用这个数与其它字符串的Hash值进行比对。(可配合hash表一起使用)

二.字符串Hash原理

取一固定值base,把字符串看作base进制数,并分配一个大于0的数值,代表每种字符。一般来说,对每种字符的分配值都小于base(可以直接使用字符的Ascall值)。但是,字符串用base进制数表示后一般会很大,通常取一固定值M,作为模数对每个字符串所对应的base进制数取模
一般我们取base=131 或 base=13331。取M=2^64,即直接unsigned long long 类型存储字符串的Hash值(ull 的自然溢出相当于对2^64取模,且能够避免低效的取模(mod)运算)。此时Hash值产生冲突的概率极低,如果两个字符串Hash值相同,就可以认定这两个字符串相等

三.字符串Hash的过程
1.处理前缀

如果一个字符串S的Hash值为H(S),那么再S后加上一个字符c构成的新字符串S+c的Hash值就是H(S+c)=(H(S)×base+val[c])%Mval[c]是c的对应值。
如果一个字符串S的Hash值为
H(S)
,那么再S后加上一个字符串T构成的新字符串S+T的Hash值就是H(S+T)=(H(S)×base^lenth(T)+H(T))%M。相当于base进制下把S后边补上T个0再加上T的值。

2.查询

如果我们要查询字符串S的S[L~R]的字符串的Hash值,我们利用前缀O(1)的求出来。
H(L~R)=H( R )-( H( L-1 )* base^( R - L + 1 ) )。这也是采取了补0的方式进行的计算。

二维矩阵怎样存

其实与一维方法类似,将二维的矩阵按一定顺序看成是一维连续字符串即可

四.代码实现
//1.比对一个字符串L1~R1的子串与L2~R2的子串是否相等。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef unsigned long long ull;
int n;
string s;
int base=131,L1,R1,L2,R2;
ull val[N],B[N];
void Get_hash(string s){//预处理求出前缀子串的Hash值
	B[0]=1;//预处理base进制数的数组,B[i]表示base^i
	for(int i=0;i<s.size();i++){
		val[i+1]=val[i]*base+(ull)(s[i]);
		B[i+1]=B[i]*base;		
	}

}
ull V(int L,int R){//查询S[L~R]的值
	ull k=(val[R]-(val[L-1]*B[R-L+1]));
	return k;
}
int main(){
    cin>>s;
    Get_hash(s);
    scanf("%d",&n);
    while(n--){
    	scanf("%d%d%d%d",&L1,&R1,&L2,&R2);
    	if(V(L1,R1)==V(L2,R2)) printf("Yes\n");
    	else printf("No\n");
	}
	return 0;
}


//2.查找一个字符串是否已经存在
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=1e6+25;
struct node{
	ull val;
	int last;
}h[N+10];//开hash表来存字符串的Hash值
int tot,n,p=50021,base=131,head[N];
string s;
ull H(string s){//求字符串Hash值
	ull val=0;
	for(int i=0;i<s.size();i++){
		val=val*base+(ull)(s[i]);
	}
	return val;
}
bool Find(ull val){
	int k=val%p;
	for(int i=head[k];i!=-1;i=h[i].last){
		if(h[i].val==val) return 1;//找到相同的Hash值,即出现过
	}
	return 0;
}
void Insert(ull val){//将Hash值插入,而不是字符串
	int k=val%p;
	h[++tot].val=val;
	h[tot].last=head[k];
	head[k]=tot;
}
int main(){
	memset(head,-1,sizeof(head));
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		cin>>s;//输入字符串
		ull X=H(s);//取其Hash值,并用这个值代替字符串s
		if(!Find(X)) Insert(X);//找不到就插入
		else printf("%d\n",i);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值