一、例题引入

Acwing 字符串哈希

给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 l1,r1,l2,r2,请你判断 [l1,r1] 和 [l2,r2] 这两个区间所包含的字符串子串是否完全相同。字符串中只包含大小写英文字母和数字。输入格式
第一行包含整数 n 和 m,表示字符串长度和询问次数。第二行包含一个长度为 n 的字符串,字符串中只包含大小写英文字母和数字。接下来 m 行,每行包含四个整数 l1,r1,l2,r2,表示一次询问所涉及的两个区间。注意,字符串的位置从 1 开始编号。输出格式
对于每个询问输出一个结果,如果两个字符串子串完全相同则输出 Yes,否则输出 No。每个结果占一行。数据范围
1≤n,m≤1e5
输入样例:
8 3
aabbaabb
1 3 5 7
1 3 6 8
1 2 1 2
输出样例:
Yes
No
Yes

二、算法讲解

字符串前缀哈希法:把字符串变成一个p进制数字(哈希值),实现不同的字符串映射到不同的数字。
对形如 X1X2X3⋯Xn−1XnX1X2X3⋯Xn−1Xn 的字符串,采用字符的ascii 码乘上 P 的次方来计算哈希值。

映射公式 (X1×Pn−1+X2×Pn−2+⋯+Xn−1×P1+Xn×P0)modQ(X1×Pn−1+X2×Pn−2+⋯+Xn−1×P1+Xn×P0)modQ
注意点:

  1. 任意字符不可以映射成0,否则会出现不同的字符串都映射成0的情况,比如A,AA,AAA皆为0
  2. 冲突问题:通过巧妙设置P (131 或 13331) , Q (264)的值,一般可以理解为不产生冲突。

问题是比较不同区间的子串是否相同,就转化为对应的哈希值是否相同。
求一个字符串的哈希值就相当于求前缀和,求一个字符串的子串哈希值就相当于求部分和。

  • 前缀和公式 h[i+1]=h[i]×P+s[i]h[i+1]=h[i]×P+s[i] i∈[0,n−1]i∈[0,n−1] h为前缀和数组,s为字符串数组
  • 区间和公式h[l,r]=h[r]−h[l−1]×Pr−l+1h[l,r]=h[r]−h[l−1]×Pr−l+1
    • 区间和公式的理解: ABCDE 与 ABC 的前三个字符值是一样,只差两位,
      乘上P2 把 ABC 变为 ABC00,再用 ABCDE - ABC00 得到 DE 的哈希值。

三、代码实现

//#pragma GCC optimize(2)
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<ctime>
#include<cstring>
#include<list>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef  pair<int, int> PII;const int N = 1e6 + 7,P=131;ull hx[N],p[N];   //用unsigned long long 来处理取模2^64的操作
/*hx[i]代表字符串前i位的哈希值,p[i]代表P的i次方*/ull query(int l, int r)
{return hx[r] - hx[l-1] * p[r - l + 1]; // ABCDE 与 ABC 的前三个字符值是一样,只差两位,乘上 P2 把 ABC 变为 ABC00,再用 ABCDE - ABC00 得到 DE 的哈希值。
}void solve()
{int n,m;string s;cin >> n >> m;cin >> s;hx[0] =0;  //预处理p[0] = 1;for (int i = 1; i <= n; i++){p[i] = p[i - 1] * P;   //P进制预处理hx[i] = hx[i - 1] * P + s[i - 1];  //字符串哈希处理}while (m--){int l1, r1, l2, r2;cin >> l1 >> r1 >> l2 >> r2;    //输入字串范围if (query(l1, r1) == query(l2, r2))   //字符串哈希值相同cout << "Yes\n" ;elsecout << "No\n";}
}int main()
{std::ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);solve();return 0;
}

四、注意

  • 在使用字符串哈希的时候,选取P=131或1331一般就可以避免产生哈希冲突的问题了,但是冲突的可能性并不是0,如果想要进一步避免产生哈希冲突。可以把两个字符串对两个P都求一次哈希值,如果两个p产生的哈希值都是相同的,那么就能保证没有产生哈希冲突。
  • 由于我们在代码中使用的是unsigned long long,所以我们并不需要进行取模的操作。因为如果目标数的值超过了264,unsigned long long会自动进行取余操作。

作者:Avalon Demerzel,喜欢我的博客就点个赞吧,更多图论与数据结构知识点请见作者专栏《图论与数据结构》

【数据结构】可以逃课其它字符串算法的字符串哈希算法相关推荐

  1. 数据结构与算法之美-哈希算法

    哈希算法的定义和原理 将任意长度的二进制串映射为固定长度的二进制串. 这个映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制串就是哈希值. 设计一个优秀的哈希算法需要满足: 从哈希值不能反向推 ...

  2. 一致性哈希算法 mysql_一致性哈希算法,在分布式开发中你必须会写,来看完整代码...

    今天我想先给大家科普下一致性哈希算法这块,因为我下一篇文章关于缓存的高可用需要用到这个,但是又不能直接在里面写太多的代码以及关于一致性hash原理的解读,这样会失去对于缓存高可用的理解而且会造成文章很 ...

  3. java 哈希一致算法_一致哈希算法Java实现

    一致哈希算法(Consistent Hashing Algorithms)是一个分布式系统中常用的算法.传统的Hash算法当槽位(Slot)增减时,面临所有数据重新部署的问题,而一致哈希算法确可以保证 ...

  4. 相似图像搜索的哈希算法思想及实现(差值哈希算法和均值哈希算法)

    图像相似度比较哈希算法: 什么是哈希(Hash)? • 散列函数(或散列算法,又称哈希函数,英语:Hash Function)是一种从任何一种数据中创建小 的数字"指纹"的方法.散 ...

  5. 计算机视觉的几个经典算法 —— 最小二乘法 + RANSAC + 哈希算法(附DCT) + 图像聚类算法

    计算机视觉的几个经典算法 目录 计算机视觉的几个经典算法 1. 最小二乘法(寻找线性回归函数) 2. RANSAC(模型已知,参数未知) 2.1 RANSAC 与 最小二乘法的区别 2.2 RANSA ...

  6. 【算法】一致性哈希算法原理详解

    一.普通 hash 算法 (取模算法): 在了解一致性哈希算法之前,我们先了解一下缓存中的一个应用场景,了解了这个应用场景之后,再来理解一致性哈希算法,就容易多了,也更能体现出一致性哈希算法的优点,那 ...

  7. 哈希算法——murmurhash一致性哈希算法

    Murmurhash: 是一种非加密型哈希函数,适用于一般的哈希检索操作.高运算性能,低碰撞率,由Austin Appleby创建于2008年,现已应用到Hadoop.libstdc++.nginx. ...

  8. 软考2022高级架构师下午案例分析第4题:关于哈希算法、一致性哈希算法和布隆过滤器

    目录 [说明] [问题1] [问题2] [问题3] [说明] 某大型电商平台建立了一个在线 B2B 商店系统,并在全国多地建设了货物仓储中心,通过提前备货的方式来提高货物的运送效率.但是在运营过程中, ...

  9. 什么是一致性哈希算法?一致性哈希算法原理刨析

    一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,目的是解决分布式缓存的问题. 在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系.一致性哈 ...

  10. 【算法】哈希算法——murmurhash一致性哈希算法

    Murmurhash: 是一种非加密型哈希函数,适用于一般的哈希检索操作.高运算性能,低碰撞率,由Austin Appleby创建于2008年,现已应用到Hadoop.libstdc++.nginx. ...

最新文章

  1. js图片压缩并上传?
  2. 美国一大型数据中心将24h由光伏+储能供电
  3. ETL AUTOMATION介绍
  4. 【mysql】Innodb三大特性之double write
  5. Java微服务篇3——Lucene
  6. Java 抽象类和抽象方法
  7. 一、tkinter简介
  8. 让IE中的IFrame透明
  9. idea 运行jmeter源码_IDEA 编译 Jmeter 4.0 ( 二次开发_1 )
  10. Linux操作系统主机名(hostname)简介
  11. FPS游戏UE4逆向视频教程
  12. java中讲讲PrintWriter的用法,举例?
  13. 微信支付账单修改数字
  14. js实现轮播图(简单滚动轮播)
  15. 智能定位手环方案开发
  16. 23.Android 软键盘工具ImeUtil
  17. 工业计算机发展历史,石油工业与计算机技术发展史
  18. android EditText 屏蔽长按弹出剪切 复制 全选菜单 的解决办法
  19. 什么是放量和缩量,什么是成交量
  20. Echarts图表之线性图、柱形图

热门文章

  1. HDU2044 一只小蜜蜂...
  2. 理解iOS 8中的Self Sizing Cells和Dynamic Type
  3. Linux内核等待队列wait_queue学习
  4. Net设计模式实例之享元模式( Flyweight Pattern)(1)
  5. github如何同步fork到自己仓库的代码
  6. 图像中有关位图、色位图、以及所占字节数
  7. 网易云课堂Java模拟面试笔记(31-40)
  8. 不依赖第三方环境和服务
  9. HTML5标签canvas制作动画
  10. 联通积分兑换的Q币怎么兑换到QQ上