下面这个方法来自 算法竞赛入门经典-训练指南
方法

对于一个字符串s,令h[i] = h[i+1]*x + s[i] ,其中x是你自选的一个常数。令xp[i] = xp[i-1]*x

这样之后定义s的起点为下标i,长度为len的子串的哈希值为 h[i] - h[i+len]*xp[len] 。这个值与子串的位置,子串的内容,还有你自选的常数都有关系。哈希值使用unsigned long long(如果不是oi,可以使用int128的话当然更好) 不同子串的哈希值一定不会相同吗?不一定,但是相同的概率非常非常小。如果觉得不够保险可以分别选定两次x常数,双哈希来做。
应用

  1. 找最长公共子串 http://syzoj.com/problem/186

dp超时,后缀数组RE了?(orz Fmuckss神犇),后缀自动机不会写?来写易于理解速度也相当不错的哈希吧。

这里有两个字符串,分别给两个字符串做哈希,然后二分直接二分答案len,计算两个字符串每个起点开始长度为len的子串的哈希(O(n)的)。然后给第两个字符串的长度为len的子串的哈希值排序。枚举第一个字符串的哈希,在第二个字符串的哈希里面用lower_bound找(这也是之前给它排序的原因,排好序就可以lower_bound),找到了就说明存在这样长度的最长公共子串。于是AC代码如下(最后总共用时约1800ms,约是后缀自动机的9倍):

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <list>
#include <queue>
#include <algorithm>
using namespace std;
typedef unsigned long long ULL;
#define MAXN 200003
ULL xp[MAXN];
ULL hasha[MAXN];
ULL hashb[MAXN];
ULL ha[MAXN];
ULL hb[MAXN];char A[MAXN], B[MAXN];
int x = 233;
int la, lb;
int mlen;
int minlen;
bool check(int len)
{for(int i = 0; i < la-len+1; i++)hasha[i] = ha[i] - ha[i+len]*xp[len];for(int i = 0; i < lb-len+1; i++)hashb[i] = hb[i] - hb[i+len]*xp[len];sort(hashb, hashb+lb-len+1);for(int i = 0; i < la-len+1; i++){ULL h = hasha[i];int p = lower_bound(hashb, hashb+lb-len+1, h)-hashb;if(p < lb-len+1 && h == hashb[p])return true;}return false;
}int main()
{scanf("%s %s", A, B);la = strlen(A);lb = strlen(B);mlen = max(la, lb);minlen = min(la, lb);for(int i = la-1; i >= 0; i--)ha[i] = ha[i+1]*x + A[i];for(int i = lb-1; i >= 0; i--)hb[i] = hb[i+1]*x + B[i];xp[0] = 1;for(int i = 1; i <= mlen; i++)xp[i] = xp[i-1]*x;int l = 0, r = minlen;int ans;while(l <= r){int m = (l+r)>>1;if(check(m)){ans = m;l = m+1;}elser = m-1;}printf("%d\n", ans);return 0;
}
  1. 出现次数超过m次的最长的子串 (uva 12206 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=505&problem=3358&mosmsg=Submission+received+with+ID+18140839

最长这个条件优先,因此还是二分长度。每次检查是否存在这样一个出现次数超过m次的子串即可。将哈希值排序可以把哈希值相同的子串的哈希值排在一起,这样之后就能O(n)时间判断出超过次数是否超过m次。代码

哈希用途广泛,是个非常好的东西。

/*
submition url:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=505&page=show_problem&problem=3358
*/
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <cstring>
#include <list>
#include <queue>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int m;
char str[40002];
typedef unsigned long long ULL;
ULL h[40002];
ULL hhash[40002];
ULL xp[40002];
int rrank[40002];
int x = 123;
int slen;
int pos;
bool cmp(int a, int b)
{return hhash[a] < hhash[b] || (hhash[a] == hhash[b] && a < b);
}
void calc()
{slen = strlen(str);h[slen] = 0;for(int i = slen-1; i >= 0; i--)h[i] = h[i+1]*x + str[i];xp[0] = 1;for(int i = 1; i <= slen; i++)xp[i] = xp[i-1]*x;
}
bool check(int len)
{for(int i = 0; i < slen-len+1; i++){rrank[i] = i;hhash[i] = h[i] - h[i+len]*xp[len];}sort(rrank, rrank+slen-len+1, cmp);int times = 0;pos = -1;for(int i = 0; i < slen-len+1; i++){if(i == 0 || hhash[rrank[i]] != hhash[rrank[i-1]])times = 0;if(++times >= m)pos = max(pos, rrank[i]);}return pos >= 0;
}
void solve()
{if(!check(1)){puts("none");return;}int l = 0, r = slen;int ans = 0;while(l <= r){int m = (l+r)>>1;if(check(m)){ans = m;l = m+1;}elser = m-1;}check(ans);if(ans)printf("%d %d\n", ans, pos);elseputs("none");
}
int main()
{while(true){scanf("%d", &m);if(!m)break;scanf("%s", str);calc();solve();}return 0;
}

from:http://sxysxy.org/blogs/44

zhuan [讲解] OI 字符串 常用哈希方法(by sxy sxy)相关推荐

  1. JS字符串常用属性、方法

    文章目录 属性 length constructor prototype 方法 charAt() charCodeAt() concat() indexOf() lastIndexOF() slice ...

  2. 一次性汇总了 30+ 字符串常用处理方法

    今天这篇推文我们就汇总下Python中常用的字符串处理小技巧,字符串在Python数据处理中是非常常见且极易忽略的常用数据类型,且Python本身也提供大量运算符.函数和方法来处理字符串.话不多说,接 ...

  3. 基础数据结构(二):字典树、并查集、堆、哈希表、字符串的哈希方式、STL的常见容器及其接口

    文章目录 一.字典树Trie 1 原理 2 Trie字符串统计 3 [LeetCode 208. 实现 Trie (前缀树)](https://leetcode-cn.com/problems/imp ...

  4. ML之相似度计算:图像数据、字符串数据等计算相似度常用的十种方法简介、代码实现

    ML之相似度计算:图像数据.字符串数据等计算相似度常用的十种方法简介.代码实现 目录 相似度 1.余弦相似性-夹角余弦(Cosine_Distance)距离 2.代码实现-余弦距离.余弦相似度 2.皮 ...

  5. Java中字符串的常用属性与方法

    •字符串常用的属性 string.length()---->返回字符串的长度,int类型. •字符串常用的方法 String.contains(";")------>判 ...

  6. python字符串三种常用的方法或函数_python中字符串常用的函数

    s ="hello world" s[2] >>> "l" 索引 s.index("l") >>> 2 ...

  7. ML:图像数据、字符串数据等计算相似度常用的十种方法(余弦相似性、皮尔逊、闵可夫斯基距离/曼哈顿距离/欧氏距离/切比雪夫距离、马氏距离、汉明距离、编辑距离、杰卡德相似系数、相对熵/KL散度、Helli

    ML:图像数据.字符串数据等计算相似度常用的十种方法(余弦相似性.皮尔逊.闵可夫斯基距离/曼哈顿距离/欧氏距离/切比雪夫距离.马氏距离.汉明距离.编辑距离.杰卡德相似系数.相对熵/KL散度.Helli ...

  8. C++字符串常用输入方法

    字符串常用输入方法总结 前言: 个人是从两个角度去比较思考总结的 (1)能否输入空格 (2)输入支持的是 ①单个字符 ②还是char[]字符数组 ③还是string类字符串 1.scanf(" ...

  9. 字符串的常用内置方法

    字符串的常用内置方法 capitalize() 将字符串的第一个字符转换为大写. lower() 转换字符串中所有大写字符为小写. upper() 转换字符串中的小写字母为大写. swapcase() ...

  10. python数据处理常用函数_Python中常用操作字符串的函数与方法总结

    Python中常用操作字符串的函数与方法总结 这篇文章主要介绍了Python中常用操作字符串的函数与方法总结,包括字符串的格式化输出与拼接等基础知识,需要的朋友可以参考下 例如这样一个字符串 Pyth ...

最新文章

  1. JAVA基础——编程练习(一)
  2. 论排列组合,持续更新
  3. 黑莓作为猫带笔记本上网
  4. 编码过程中的问题总结
  5. win7系统控制面板下的打开或关闭windows功能需要打开哪些功能
  6. 手把手教你C语言静态库的开发
  7. 索引中丢失 IN 或 OUT 参数
  8. 揭秘视频千倍压缩背后的技术原理之预测技术
  9. LeetCode 929. 独特的电子邮件地址
  10. matlab破损皮革定位,matlab-code-of-TDOAFDOa 干扰源定位代码,应该在 的求解过程中有帮助。 276万源代码下载- www.pudn.com...
  11. oracle em搭建,【oracle】手动安装EM
  12. BZOJ-4008: [HNOI2015]亚瑟王 (概率期望DP)
  13. typeorm实战之findOne()方法
  14. 方维直播源码无BUG修复最新版!
  15. 微信小程序云开发之云函数与本地数据库获取数据
  16. 广告行业计费模式专业术语
  17. mysql 联合主键 加锁_MySQL 加锁处理分析
  18. 从Mpx资源构建优化看splitChunks代码分割
  19. Dubbo3.0系列(6)- Dubbo3.0支持的RPC协议
  20. 读书笔记-《wxPython in Action》一

热门文章

  1. Photoshop图片秒变素描方法,非常简单
  2. Java面向对象编程(五)特殊类
  3. 互联网和人工智能之间,主要是什么关系?
  4. Linux查看mpp数据库地址,Linux环境搭建DM8 MPP双节点集群
  5. 展现量、点击量、点击率;访客数、访问次数、浏览量的区别与作用
  6. 上dnf一直连接服务器中,Win7系统下玩dnf提示正在连接服务器如何解决
  7. 全球计算机科学和电子,科学网—[转载]【喜报】祝贺IEEE TCSS入选全球计算机与电子领域Top 1000期刊 - 王飞跃的博文...
  8. 数据、程序、文件区别
  9. 《正见——佛陀的证悟》读后感
  10. C语言实现安全性极高的游戏存档并读档