字符串哈希的理解


字符串哈希


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

字符串中只包含大小写英文字母和数字。

输入格式

第一行包含整数 n 和 m,表示字符串长度和询问次数。

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

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

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

输出格式

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

每个结果占一行。

数据范围

1≤n,m≤105

输入样例:

8 3
aabbaabb
1 3 5 7
1 3 6 8
1 2 1 2

输出样例:

Yes
No
Yes

#include

using namespace std ;

typedef unsigned long long ULL ;

const int N  = 1e5+10 , P = 131; //P一般采用131,或者是13331。根据经验判断,这样的将字符串映射成为数值的时候,99%的情况下是不h

ULL h[N] , p[N] ;
//h数组其实就是可以看作是存储前缀和的数组
//p其实就是记录当前的进制的数组,当前的位数的价值可以这么理解

ULL ToPnumber(int l , int r){
    return h[r]-h[l-1]*p[r-l+1] ;  
}

/*这个思想就比较妙了,想要算出有固定起始区间的一段字符串的P进制数,其实可以拿少的数扩展来进行相减。
举个例子,比如一段数组453672,我想要计算出来3~5区间的数值即367.我可以用45367-45*10的(5-3+1)次方。
同样的道理,想要算出l~r的区间代表的P进制的数字,目前有已知h[r]和h[l].直接return h[r]-h[l-1]*(r-l+1) ;
*/

int main(){
    int n , m ;
    cin>>n>>m ;
    string x ;
    cin>>x ;
    h[0] = 0 ; p[0] = 1 ;
    
    for(int i = 0 ;i < n ;++i)
    {
        p[i+1] = p[i]*P  ;
        h[i+1] = h[i]*P + x[i] ; //这就是算前缀和的操作
    }
    
    for(int i = 0 ; i < m ;++i)
    {
        int l1 , l2 , l3 ,l4 ;
        cin>>l1>>l2>>l3>>l4 ;
        if(ToPnumber(l1,l2) == ToPnumber(l3,l4))
            cout<<"Yes"<< endl ;
        else 
            cout<<"No"<< endl ;
    }    
    return  0 ;
}

文章作者: 罗林
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 罗林 !
  目录