c++acwing841.字符串哈希

给定一个长度为 n
 的字符串,再给定 m
 个询问,每个询问包含四个整数 l1,r1,l2,r2
,请你判断 [l1,r1]
 和 [l2,r2]
 这两个区间所包含的字符串子串是否完全相同。

字符串中只包含大小写英文字母和数字。
输入格式
第一行包含整数 n
 和 m
,表示字符串长度和询问次数。

第二行包含一个长度为 n
 的字符串,字符串中只包含大小写英文字母和数字。

接下来 m
 行,每行包含四个整数 l1,r1,l2,r2
,表示一次询问所涉及的两个区间。

注意,字符串的位置从 1
 开始编号。

输出格式
对于每个询问输出一个结果,如果两个字符串子串完全相同则输出 Yes,否则输出 No。

每个结果占一行。

数据范围
1≤n,m≤105

此题只是其中一例,本萌新认为此算法比较重要,核心思想是把字符串转化成一个值,然后就可以分别与其他的字符串比较来看两串是否相同,我们知道十进制十进一,二进制是二进一,在此我踩在前人肩膀上,取此值为131,即131进一(前缀和的思想来模拟进位),而我们还需要考虑值的大小问题,在此又可借鉴前人之智慧,取2的64次方,而unsigned long long 刚好是所需值,为方便理解前缀和,字符串的录入从下标为1的开始。

此题是求一个字符串中指定字串是否相等,我们用p数组来模拟的进位,即类似于十进制的个十百千万位,用d[ i ]数组来表示从下标1到i的s字符串的大小

第二个图是表示d数组,即映射值,d1表示s[1]的哈希值,d2表示s[2]的哈希值, 我们要求l到r的哈希值,而我们已知d[ l -1]和d[ r ],此时我们可以利用d[ r ]-d[l-1]*p[r-l+1]来表示其哈希值。例如字符串ccbbddb,l=3,r=6,整个字符串转化为p进制为(ccbbddb)p,而s[ l-1 ]为(cc)p,s[r]为(ccbbdd)p,当s[ l -1]*p[r-l+1]为(cc0000),相减后就为(bbddb)p,此时发现就是所求的哈希值。

加入代码解释,如若不理解,萌新入住,胆小勿喷。

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010,P=131;//P为p进制 
char s[N];//此来存储字符串 
unsigned long long p[N],d[N];//开2的64次方来进行存储数据,p数组是代表进位,即p,p*p,p*p*p……,类似十进制 
int Haxistring(int l,int r)
{
    return d[r]-d[l-1]*p[r-l+1];//此不在赘述 
}
int main()
{
    int n,m;//n为字符串长度,m为多少次询问 
    scanf("%d%d%s",&n,&m,s+1);//s+1是将s[1]作为开端,众所周知,指针后移1 
    p[0]=1;//给其初值,为前缀和形式求进位做准备 
    for(int i=1;i<=n;i++)//从一开始,利于理解,更方便 
    {
        p[i]=p[i-1]*P;//求进位 
        d[i]=d[i-1]*P+s[i];//利于前缀和求s[1]到s[1],s[2],s[……],s[n]之间的哈希值 
    }
    while(m--)
    {
        int l1,l2,r1,r2;
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        if(Haxistring(l1,r1)==Haxistring(l2,r2)) puts("Yes");
        else puts("No");
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

jdsdyy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值