字符串哈希

目录

问题描述

字符串哈希

具体步骤

①先确定一套进制。

②将a前缀以及b转化成为哈希值。

③如何让a数组保持一个长度窗口滑动

④最后进行哈希值的比较即可

一些小细节


 

问题描述

大家在刷算法的时候一定有听过这样的算法题目。如果给你一个较长的字符串a,以及一个较短的字符串b,然后问b是否是a的一个子串,如果是的话,b在a中出现了几次?大家一开始见到这个题目的时候无疑不会想到一种暴力的解法,就是让b串一个一个往后移动跟a进行比较。就像:

这样的方法显然当数据大了的时候会超时,因此下面引入字符串哈希。

字符串哈希

其实在听到这个名字的时候,以为很高端,其实不然,其实质就是将b串通过一些转化变为哈希值,然后a对应长度的字符串也转变成一个哈希值。最后将两个哈希值进行比较,如果相等的话,那么这两个字符串也已经大概率是相同了的。为什么我会说大概率呢?因为我们没有办法保证哈希值相同的两个字符串一定就是相同的,这就涉及到了所谓的“哈希冲突”,其实昨天在学到这的时候就觉得数据结构真的是非常,非常的有趣啊!当然因为自己的蒟蒻,所以这里奉上一个力扣神犇在解释字符串哈希的博客,相信都会有所收获:here。

具体步骤

①先确定一套进制。

转化一个字符串变成哈希值,我们需要确定是在哪一个进制下转化的,当然为了避免人为主观性,我们可以采取随机化一个进制,定为在r进制下的哈希值。

②将a前缀以及b转化成为哈希值。

下面以b的长度为3举例子,这里涉及到了,进制如何进行转化哦,敲黑板敲黑板!

int pre1=0,pre2=0;
	for(int i=0;i<3;i++)
	{
		pre1=(pre1*r%131+(a[i]-'0'))%131;
		pre2=(pre2*r%131+(b[i]-'0'))%131;
	}

③如何让a数组保持一个长度窗口滑动

也就是说aaa和bcd算出来哈希值不同之后,我们自然会比较aab和bcd一直是abb,bbc,bcd......如何做到a字串保持3个字符的窗口滑动呢?有一种方法是,直接再次重新算一遍呗!但是其实会有更好的办法,以14413为例子。(在10进制下)如何从144变为441呢?首先我们要去掉第一个1,即用144-1*100=44,然后44*10=440,最后440+1=441;相信聪明的你看出来了其中的做法。首先我们要用原来哈希值减去(首位*pow(r,n-1))r是进制的数,n代表b的字符串长度,然后所得(得到的值*r)最后加上下一位即可。代码如下:

for(int i=0;i<7;i++)
	{
		pre1=(pre1-(a[i]-'0')*k%131)*r%131+(a[i+3]-'0')%131;
		if(pre2==pre1)
		sum++;
	 }

④最后进行哈希值的比较即可

最终的相关代码(我是用特殊例子进行测试的)

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int sum=0;
	char a[100];
	char b[10];
	for(int i=0;i<10;i++)
	cin>>a[i];
	for(int i=0;i<3;i++)
	cin>>b[i];
	int k=100%131;
	int r=10%131;
	int pre1=0,pre2=0;
	for(int i=0;i<3;i++)
	{
		pre1=(pre1*r%131+(a[i]-'0'))%131;
		pre2=(pre2*r%131+(b[i]-'0'))%131;
	}
	cout<<pre1<<endl;
	cout<<pre2<<endl;
	if(pre2==pre1)
		sum++;
	for(int i=0;i<7;i++)
	{
		pre1=(pre1-(a[i]-'0')*k%131)*r%131+(a[i+3]-'0')%131;
		cout<<pre1<<endl;
		if(pre2==pre1)
		sum++;
	 } 
	 cout<<sum<<endl;
}

这是测试的数据,然后最后的sum表示相同的有3个哦。

一些小细节

其实看到这里很多人应该会懵逼,为什么中途的代码每一个都mol上了一个质数,其实是因为在不知道自己的进制是多少的情况下,如果不在计算的过程中进行相关的取模,我们很有可能让一个非常非常大的数字爆掉我们的电脑,这就十分可怜啦!其实这样的方法是不完善的,依然会存在哈希冲突的可能,如果要完全正确,可以考虑利用两个进制去约束,或者在哈希值相同的情况下让出于框内的两个字符串依次进行比较哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sheep.ice

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值