AcWing 841.字符串哈希

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

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

输入格式

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

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

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

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

输出格式

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

每个结果占一行。

数据范围

1≤n,m≤10^5

输入样例:

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

输出样例:

Yes
No
Yes

       这里回忆一下传统的线性探查法的哈希方式:题目输入了a1,a2,a3,......ai-1,ai,ai+1,.....an,然后给我们一个数x,问我们这个数在不在刚才输入的数据里。这种题目我们就是先声明一个数组,然后将刚刚输入的一堆数据的通过某种手段映射成下标,然后在该下标的位置存储起来,这样查询一个数时,我们就可以根据数值算出它对应的下标,如果该下标处是空的,就说明没有,如果存在就是有。

        不过这都是理想情况,事实上在实现的时候,我们就是根据数据规模声明一个较大的数组,改数组长度是数据规模的2~3倍,例如数据规模是n,那么我们就声明一个大小为2n的数组,设N=2*n,那么映射下标的公式就是:int k = (x%N+N)%N,说白了就是取个模,不过当x小于N时,取模的结果是负数,下标不能是负的呀,所以我们再加上一个N,然后再取模一次。通过约定了这样一个存数的规则,我们就实现了数值和下标的转换,不过显而易见的是,我们这样做,肯定会发生冲突,也就是当两个数取模之后结果相同,该怎么办呢,解决方法就是如果算出来下标之后该下标的位置上有数字,就沿着该下标往后找,如果有空位置就填在该处,这就是线性探查法的思路,通过值算出下标,那么该在下标到往后不远的范围内,一定可以找到这个数(如果该数存在的话,如果不存在就会往后找的时候就会遇到空位置)。

字符串哈希和线性探查法完全是两种东西,字符串哈希就是给你一个很长的字符,然后问你其中两段子串是否相等,肯定不能用暴力,要不铁超时,先对这个长的字符串进行一个哈希:将一个长的字符串转换成一个P进制的数字,通过这种方式,我们能算出来它任意两个子串的哈希值,通过对比哈希值就能知道两个串是否相等。P进制我们就用131进制,然后数的大小就是2^64-1,这是固定套路,用131几乎不会产生冲突,就是两个不同的字符串却映射成同一个哈希值的现象不会发生。然后我们就可以写代码了,具体内容注释写的很细。

AC代码 

/*字符串哈希就是通过将某一个长的字符串转换成一个数字
*然后可以算出子串的哈希值,这样就可以知道该字符串的任意两个子串是否相等
* 固定套路就是将该字符串转成131进制的数字,然后用unsigned long long储存哈希值
*/

#include<iostream>
#include<string>
using namespace std;
typedef unsigned long long ULL;
const int N = 100010, P = 131;
ULL p[N], h[N];
int query(int l, int r) {
	/*我们已经知道0-l的哈希值和0-r的哈希值,据此我们可以计算出l-r的哈希值
	* 假如P为10,字符串“12345”,需要计算第3(l)位到第5(r)位的哈希值
	* 其实在10进制下一眼就能看出来是345,怎么算的呢,就是h[5]-h[2]*p[5-2],即12345-12*10^3=12345-12000=345;
	*/
	return h[r] - h[l - 1] * p[r - l + 1];
}
int main(void) {
	int n, m; cin >> n >> m;
	string str; cin >> str;
	//类似于初始化
	p[0] = 1;
	h[0] = 0;
	for (int i = 0; i < n; i++) {
		p[i + 1] = p[i] * P;//p[i]表示第i位字母占的权值,例如p[2]表示第2位是p的平方,类似于十进制下的10的平方
		h[i + 1] = h[i] * P + str[i];
		/*h[i]表示0-i字符串对应的哈希值,因为我们将一个字符串转换成了一个P进制的数字
		* 例如123这个数字,假如p等于10,那么h[1]表示‘1’对应的哈希值,为 str[1],即为1 ;
		* h[2]表示‘12’对应的哈希值,为h[1]*10+str[1],即1*10+2=12;
		* h[3]表示‘123’对应的哈希值,为h[2]*10+str[2],即10*10+3=123
		* 通过h[i+1]=h[i]*p+str[i]的公式就计算出了0-i的所有哈希值,只不过在本题里面将str[i],也就是ascll码值当做值
		*/
	}
	while (m--) {
		int l1, r1, l2, r2;
		cin >> l1 >> r1 >> l2 >> r2;
		if (query(l1, r1) == query(l2, r2))cout << "Yes" << endl;
		else cout << "No" << endl;
	}
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
字符串哈希算法是一种将字符串映射为数字的算法,常用于字符串的比较和匹配。在C++,可以使用字符串哈希算法来加速字符串的比较操作。 引用\[1\]的代码示例展示了一个使用字符串哈希算法C++代码。该代码使用了前缀和数组和字符串数组来存储字符串,并通过计算哈希值来比较两个子串是否相等。其哈希值的计算使用了前缀和数组和幂运算。 引用\[2\]的解释指出,使用字符串哈希的目的是为了比较字符串时不直接比较字符串本身,而是比较它们对应映射的数字。这样可以将子串的哈希值的时间复杂度降低到O(1),从而节省时间。 引用\[3\]的代码示例也展示了一个使用字符串哈希算法C++代码。该代码使用了前缀和数组和字符串数组来存储字符串,并通过计算哈希值来比较两个子串是否相等。与引用\[1\]的代码类似,哈希值的计算也使用了前缀和数组和幂运算。 综上所述,字符串哈希算法是一种将字符串映射为数字的算法,常用于字符串的比较和匹配。在C++,可以使用前缀和数组和幂运算来计算字符串哈希值,并通过比较哈希值来判断两个子串是否相等。 #### 引用[.reference_title] - *1* [C++算法题 # 33 字符串哈希](https://blog.csdn.net/weixin_44536804/article/details/123425533)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [字符串哈希(c++)](https://blog.csdn.net/qq_41829492/article/details/120980055)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [AcWing 841. 字符串哈希C++算法)](https://blog.csdn.net/YSA__/article/details/108453403)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值