字符串哈希算法

字符串哈希,最著名的就是BKDRHash,也就是将字符串变成数值,并且最后变成的数值是一个P进制的数(一班取131或者13331),一般来说P最好为素数.然后我们之所以需要前缀和,是因为我们这道题目是求一个区间的字符串,又因为是哈希表,所以我们得求出区间哈希和,又因为是是区间和,所以我们得用前缀和求O(n)预处理,来实现和哈希一般的O(1)常数级别查询.这种Hash常用,且冲突概率极低,offer必备,同时竞赛OI党必备,是优秀的算法,容易精简易理解.

例题1:AcWing——兔子与兔子

很久很久以前,森林里住着一群兔子。

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

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

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

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

输入格式

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

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

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

输出格式

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

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

数据范围

1≤length(S),m≤10000001≤length(S),m≤1000000
输入样例:

aabbaabb
3
1 3 5 7
1 3 6 8
1 2 1 2
输出样例:

Yes
No
Yes

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N=1000010,base=131;//进制
char str[N];
ULL h[N],p[N];              //h数组是求前缀哈希值,p数组是求进制的i次幂ULL get(int l,int r){      //求一段区间的哈希值return h[r]-h[l-1]*p[r-l+1];
}int main(){scanf("%s",str+1);int n=strlen(str+1);   //从str[1]开始存p[0]=1;for(int i=1;i<=n;i++){h[i]=h[i-1]*base+str[i]-'a'+1;  //利用前缀和的思想求哈希值p[i]=p[i-1]*base;}int m;cin>>m;while(m--){int l,r,x,y;scanf("%d%d%d%d",&l,&r,&x,&y);if(get(l,r)==get(x,y))cout<<"Yes"<<endl;elsecout<<"No"<<endl;}return 0;
}

例题2:139. 回文子串的最大长度

如果一个字符串正着读和倒着读是一样的,则称它是回文的。

给定一个长度为N的字符串S,求他的最长回文子串的长度是多少。

输入格式

输入将包含最多30个测试用例,每个测试用例占一行,以最多1000000个小写字符的形式给出。

输入以一个以字符串“END”(不包括引号)开头的行表示输入终止。

输出格式

对于输入中的每个测试用例,输出测试用例编号和最大回文子串的长度(参考样例格式)。

每个输出占一行。

输入样例:

abcbabcbabcba
abacacbaaaab
END

输出样例:

Case 1: 13
Case 2: 6

前缀和+后缀和+二分+Hash(哈希) O(nlogn)
我们发现0这道题目数据范围极其恐怖,那么只有一个办法可以让我们求解这道题目,那就是哈希,或者是O(n)复杂度的Manacher算法,但是我们这道题目是锻炼我们的哈希水平,所以我们这里只说如何用哈希算法求解.作者目前还不会马拉车算法,作者先去学一下再来补

上一道兔子兔子兔子的题目,我们知道判断两个字符串是否相等,可以使用字符串哈希,也就是将字符串算成P进制数值,然后区间和判断即可,那么这道题目我们需要一个正的字符串,还需要一个反的字符串,然后如果正字符串等于反的字符串,那么奇数回文串就2+1,偶数回文串就直接2即可.之所以要这么做,因为我们是要回文对不对,我们需要将回文拆解成为一个正字符串和一个反字符串,这样才好处理这道题目.

既然如此,我们可以算出一个前缀和,再算出一个后缀和,然后就可以知道,正字符串和一个反字符串.字符串的哈希值就是这个区间的哈希值和.

算完之后,我们当前就只需要枚举一个mid中间点,因为所有回文串都是有一个中间点(奇),或者中间区间(偶),然后二分分别寻找这个字符串长度即可,记住不是回文串,回文串的长度,是字符串长度* 2 + 1(奇) 或者是字符串长度 * 2(偶数).

切记如果说这个最大回文串为1(也就是所有字符都不一样,比如说abcdefg),那么输出是1,不是3,奇数回文串=奇数字符串*2+1,你们要小心特判这种情况,或者处理二分边界.

#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define fir(i,a,b) for(int i=a;i<=b;i++)
#define fic(i,a,b) for(int i=a;i>=b;i--)
#define Mod 131 //P进制
const int N=1000007;
char s[N];
ull f1[N],f2[N],p[N];
int ans,t,l,r,mid;
ull Hash1(int i,int j)//正字符串的哈希值
{return (f1[j]-f1[i-1]*p[j-i+1]);
}
ull Hash2(int i,int j)//反字符串的哈希值
{return (f2[i]-f2[j+1]*p[j-i+1]);
}
void init()
{p[0]=1;//p^0为1fir(i,1,N-1)p[i]=p[i-1]*131;//P进制的位值
}
int main()
{init();while (++t){ans=0;scanf("%s",s+1);int len=strlen(s+1);if (strcmp(s+1,"END")==0) //结束读入return 0;f2[len+1]=0;//初始化要注意,不然的话容易GGfir(i,1,len) f1[i]=f1[i-1]*Mod+(s[i]-'a'+1);//前缀和fic(i,len,1)f2[i]=f2[i+1]*Mod+(s[i]-'a'+1);//后缀和fir(i,1,len){l=0,r=min(i-1,len-i);//二分枚举长度为奇数的字符串 记住这里l一定要为0,不然的话,你会发现最后一个数据会卡死你.while(l<r){mid=l+r+1>>1;if (Hash1(i-mid,i-1)==Hash2(i+1,i+mid))//如果这是一个回文串的话l=mid;elser=mid-1;}ans=max(l<<1 | 1,ans);//算出最大长度l=0,r=min(i-1,len-i+1);//偶数字符串while (l<r){mid=l+r+1>>1;if (Hash1(i-mid,i-1)==Hash2(i,i+mid-1))//check判断l=mid;elser=mid-1;}ans=max(l<<1,ans);//偶数字符串只需要*2}printf("Case %d: %d\n",t,ans);}return 0;
}

马拉车算法:代码有详细注释

#include<bit/stdc++.h>
#define Min(a,b) a>b?b:a
#define Max(a,b) a>b?a:b
using namespace std;
int Len[3000005];  //记录每个位置的最长回文子串的长度
char str[3000005],s[3000005];
int n,mx,id,len;  //mx记录前面最长回文串的最右位置,id记录前面最长回文子串的下标void init(){  //初始化函数,将字符串中插入特殊字符int k=0;  str[k++] = '$';  for(int i=0;i<len;i++){  str[k++]='#';  str[k++]=s[i];  }  str[k++]='#';  len=k;
}  int Manacher(){  Len[0] = 0;  int sum = 0;  mx = 0;  for(int i=1;i<len;i++){  if(i < mx) Len[i] = Min(mx - i, Len[2 * id - i]);  //如果当前位置比最右位置小,更新当前位置的长度else Len[i] = 1;  //比最右位置大,则只能一位一位枚举计算最大回文子串while(str[i - Len[i]]== str[i + Len[i]]) Len[i]++;  if(Len[i] + i > mx){//如果当前位置的回文子串的最右位置大于前面的,就更新其值  mx = Len[i] + i;  id = i;      sum = Max(sum, Len[i]);  //用sum来记录最大的回文子串长度}  }  return (sum - 1);
}  int main()
{  scanf("%d",&n);  while(n--){  memset(str,0,sizeof(str));scanf("%s",s);  len = strlen(s);  init();  int temp = Manacher();  printf("%d\n",temp);  }  return 0;
}  

字符串哈希算法简单入门学习相关推荐

  1. 【学习笔记】网络流算法简单入门

    [学习笔记]网络流算法简单入门 [大前言] 网络流是一种神奇的问题,在不同的题中你会发现各种各样的神仙操作. 而且从理论上讲,网络流可以处理所有二分图问题. 二分图和网络流的难度都在于问题建模,一般不 ...

  2. 机器学习 —— KNN算法简单入门

    机器学习 -- KNN算法简单入门 第1关:手动实现简单kNN算法 1 KNN算法简介 1.1 kNN 算法的算法流程 1.2 kNN 算法的优缺点 1.3 编程要求+参数解释 2. 代码实现 3. ...

  3. ELFhash - 优秀的字符串哈希算法

    原 ELFhash - 优秀的字符串哈希算法 分类:算法杂论算法精讲数据结构 (1424)  (2) 1.字符串哈希: 我们先从字符串哈希说起 在很多的情况下,我们有可能会获得大量的字符串,每个字符串 ...

  4. 算法竞赛入门学习(篇一)

    算法竞赛入门学习 算法竞赛入门学习,本文习题来自牛客网教程. 一.枚举与贪心 优化枚举的基本思路,减少枚举次数 选择合适的枚举对象 选择合适的枚举方向--排除非法或不是最优的情况 选择合适的数据维护方 ...

  5. JS简单入门学习笔记一

    JS的HelloWorld 在页面中输出一个内容 document.write(); 向控制台输出一个内容 console.log(); /**1.JS中严格区分大小写*2.JS中每一条语句以分号结尾 ...

  6. Java中的Hash值的计算方式,java哈希算法简单数据类型的具体实现

    最近被提及Java中HashMap的一些实现及哈希冲突等,借鉴了一位老哥的部分解析,比较明白的展示hash算法的应用吧 结论: 对于String.Integer等类复写了Object中的hashCod ...

  7. MySQL数据库 sql语句的简单入门学习

    初步学习MySQL后的一些总结 MySQL简介 MySQL在过去由于性能高.成本低.可靠性好,已经成为最流行的开源数据库,因此被广泛地应用在Internet上的中小型网站中.随着MySQL的不断成熟, ...

  8. Linux简单入门学习

    文章目录 一.入门概述 1.我们为什么要学习Linux 2.Linux简介 3.Linux的发行版本 二.Linux安装 1.虚拟机安装(耗资源) 2.购买云服务器(推荐) 三. Linux文件系统 ...

  9. Pygame简单入门学习笔记

    首先先放出我的第一个使用Pygame写的程序"菜虚鲲大战蔡徐坤". import random import pygame import sys import time pygam ...

最新文章

  1. python messagebox一定要指定父窗体吗,为什么要使用的MessageBox.show一个所有者窗口?...
  2. 淘宝直播应关注哪些方面?
  3. 苹果春季发布会:绝不玩别人玩剩下的!
  4. 迭代器适配器{(插入迭代器back_insert_iterator)、IO流迭代器(istream_iterator、ostream_iterator)}...
  5. 第二章节 变量与数据类型
  6. 五万字整理Mybatis 入门只需要一篇文章
  7. Raspberry Pi网络监控
  8. 小米浏览器地址栏欺骗漏洞原理与利用分析
  9. ALSA 音频工具 amixer、aplay、arecord
  10. 入侵检测系统,浅析几个著名的入侵检测系统
  11. [python复习8] 数据库mysql操作
  12. easyUI的基本知识
  13. 短视频app开发:如何实现视频直播功能
  14. 如何组建游戏制作团队?团队人员如何寻找?
  15. IDEA 配置Go环境,编写Golang代码,学习笔记(一)
  16. sunspot solr
  17. 计算机图形学 使用OpenGL的场景建模
  18. 国科大 - 自然语言处理(刘洋)- 期末复习
  19. oracle矩阵转置,法线变换、逆转置、伴随转置
  20. 一对一辅导价格表初中_初中一对一辅导价格多少

热门文章

  1. Java中集合类的关系图
  2. java程序运行内存分配不足_解决Tomcat运行内存不足问题
  3. 【SQL基础】,入门级必备,SQLserver MySQL
  4. mysql 存储过程 数字相加_mysql 存储过程 数字相加
  5. 解决Eclipse中SVN图标不显示的问题
  6. 云服务器的一些终端命令与安装tyk_gateway
  7. shell 实现MHA的master_ip_failover
  8. Windows CreateEvent,SetEvent,WaitForSingleObject的用法
  9. Oracle11g DG实战配置(Windows版)(五)主备库DG配置
  10. vim 如何跳转到函数定义