字符串Hash

1.字符串Hash概念
简单来说字符串Hash就是将一个字符串转化成一个整数,并保证字符串不同,得到的Hash值不同,这样就可以用来判断一个该字串是否重复出现过。

2.Hash方法
给定一个字符串s[ n ]=s[0]s[1]s[0]…s[n-1],
对于字母是s[ i ],我们规定 idx[ s[i] ]=x-‘a’+1。(当然也可以直接用s[ i ] 的ASCII值)

1,自然溢出法
unsigned long long Hash[n],
hash[ i ]=hash[i−1]∗p+idx(s[i])

2,单Hash法
hash[i]=( (hash[i−1])∗p+idx(s[i]) ) % mod
其中p和mod均为质数,且有p<mod。
对于此种Hash方法,将p和mod尽量取大即可,这种情况下,冲突的概率是很低的。

3.求子串的Hash值
一个字符串 s1s2s3s4的hash值
hash[1]=s1
hash[2]=s1∗p+s2
hash[3]=s1∗p^2+s2∗p+s3
hash[4]=s1∗p^3+ s2∗p^2+s3∗p+s4
现在我们想求s3s4的hash值,不难得出为s2*p+s3
故可以归纳出以下结论
hash = hash[ r] - hash [l - 1]p^(r- l+ 1).
如果需要反复对子串求解hash值,预处理p的n次方效果更佳。

4.例题
很久很久以前,森林里住着一群兔子。

有一天,兔子们想要研究自己的 DNA 序列。

我们首先选取一个好长好长的 DNA 序列(小兔子是外星生物,DNA 序列可能包含 26 个小写英文字母)。

然后我们每次选择两个区间,询问如果用两个区间里的 DNA 序列分别生产出来两只兔子,这两个兔子是否一模一样。

注意两个兔子一模一样只可能是他们的 DNA 序列一模一样。

输入格式
第一行输入一个 DNA 字符串 S。

第二行一个数字 m,表示 m 次询问。

接下来 m 行,每行四个数字 l1,r1,l2,r2,分别表示此次询问的两个区间,注意字符串的位置从1开始编号。

输出格式
对于每次询问,输出一行表示结果。

如果两只兔子完全相同输出 Yes,否则输出 No(注意大小写)。

数据范围
1≤length(S),m≤1000000
输入样例:
aabbaabb
3
1 3 5 7
1 3 6 8
1 2 1 2
输出样例:
Yes
No
Yes

代码实现

#include<stdio.h>
#include<string.h>
int hash[1000010],p=133,pi[1000010];
unsigned long long hashi(int l,int r)//获取子串hash值的函数
{
    return (hash[r]-hash[l-1]*pi[r-l+1]);
}
int main()
{
    char a[1000010];
    while(scanf("%s",a)!=EOF)
    {
        int i,len;
        len=strlen(a)+1;
        for(i=len; i>=0; i--)
            a[i]=a[i-1];//hash值从1开始,故将字符串向后移一位
        for(i=1,hash[0]=0,pi[0]=1; i<=len; i++)
        {
            hash[i]=hash[i-1]*p+a[i]-'a'+1;//计算hash值
            pi[i]=pi[i-1]*p;//将p的几次方以数组形式预处理
        }
        int m,l1,r1,l2,r2;
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            if(hashi(l1,r1)==hashi(l2,r2))//判断子串hash值是否相等
                printf("Yes\n");
            else
                printf("No\n");
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值