关于HASH

​ 这应该是经常使用的一个算法,因为其预处理后,优秀的\(O(1)\)处理出子串,并且\(O(1)\)比较,大快人心,而且写法简单,令人心情愉悦;

​ 但是其空间复杂度较高,并且有玄学模数以及哈希冲突,以至于如果想hack,其实可以hack掉;

前置知识

​ 关于进制,模数,hash就用到了重构进制,取模稀疏,所以哈希表又叫稀疏表;

入坑

​ hash很好理解,而且匹配非常方便,不容易写炸,对于萌新十分友好,

HASH查询

​ 我们知道数字匹配复杂度为 \(O(1)\) ,数字匹配速度快,而字符串却只能一个一个匹配, 这不公平 .那么我们考虑将字符串变成数字.

​ 想一下数字有进制,那么我们定义一下字母的进制,不一定是26,我们可以随便取一个数,习惯性取质数;

​ 但是数字太长,爆 \(long\) \(long\) 我们没办法存怎么办,我们考虑字符串很少,但是空间很大,我们考虑将数字安排入一个位置,其实这个位置是随机的,但是我们可以推出,这就够了;

​ 那么我们可以模一个数字,将数字限制在一个范围之内,然后储存下来,而这个模数一般是一个质数,因为质数的特殊性质,可以造成更好地将数字稀疏;

模版

#define ll long long
const ll base=133;
const ll mod=19491001;
ll id(char s[]){
int l=strlen(s);ll ol=0;
for(int i=0;i<l;i++)
ol=(ol*base+s[i]-'a'+1)%mod;
return ol;
}

​ 处理复杂度 \(O(n)\) 然后开个数组储存即可;

HASH子串匹配

​ 我们知道,如果每次都处理出一个串的子串,那么时间复杂度 \(O(n^2)\) ,这是我们不能接受的,但是考虑一下我们存的是数字,数字有进制,那么一定可以通过加减操作得到其子串,那么,就简单很多了;

​ 我们可以先预处理出 \(HASH\) 前缀和,之后通过加减得到一段区间的子串;

​ 但是直接开数组了话,有可能开不下,或者加大hash冲突的可能(即两个字符串hash值相同),那么我们可以考虑在不超时的情况下,加入一个map储存hash值,这样不需再担心空间问题,但是每次查询时间会多一个 \(logn\) ,请谨慎使用;

例题

​ 我不再直接附上模版,而是引入一个 例题;

给出几个由小写字母构成的单词,求它们最长的公共子串的长度。

做法

​ 我们可以二分枚举公共子串长度,因为公共子串长度一定是满足单调性质的.

​ 那么我们选择枚举第一个串的子串,然后将其他串中相同长度的子串储存起来,那么就可以匹配了;

code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define maxn 2007
#define ll long long
using namespace std;
const ll base=133;
const ll mod=998244353;
map<int,bool>ha[6];
ll sum[6][maxn],ad[maxn];
int n,lim=maxn,len[6];
char c[6][maxn]; template<typename type_of_scan>
inline void scan(type_of_scan &x){
type_of_scan f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
template<typename top,typename... tops>
inline void scan(top &x,tops&... X){
scan(x),scan(X...);
} int id(int pos,int l,int r){
return (sum[pos][r+1]-sum[pos][l]*ad[r-l+1]%mod+mod)%mod;
} bool check(int l){
for(int i=1;i<=n;i++) ha[i].clear();
for(int i=2;i<=n;i++){
for(int j=0;j+l-1<len[i];j++)
ha[i][id(i,j,l+j-1)]=1;
}
for(int i=0;i+l-1<len[1];i++){
int temp=id(1,i,i+l-1),cnt=n-1;
for(int j=2;j<=n;j++){
if(ha[j][temp]) cnt--;
}
if(!cnt) return 1;
}
return 0;
} void init(){
ad[0]=1;
for(int i=1;i<=2001;i++) ad[i]=ad[i-1]*base%mod;
for(int i=1;i<=n;i++){
for(int j=0;j<len[i];j++){
sum[i][j+1]=(sum[i][j]*base+(c[i][j]-'a'))%mod;
}
}
} int main(){
scan(n);
for(int i=1;i<=n;i++)
scanf("%s",c[i]),lim=min(len[i]=strlen(c[i]),lim);
int l=0,r=lim;init();
while(l<r){
int mid=l+r+1>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
printf("%d\n",l);
}
TO BE CONTINUED

hash应用的更多相关文章

  1. 复杂的 Hash 函数组合有意义吗?

    很久以前看到一篇文章,讲某个大网站储存用户口令时,会经过十分复杂的处理.怎么个复杂记不得了,大概就是先 Hash,结果加上一些特殊字符再 Hash,结果再加上些字符.再倒序.再怎么怎么的.再 Hash ...

  2. 对抗密码破解 —— Web 前端慢 Hash

    (更新:https://www.cnblogs.com/index-html/p/frontend_kdf.html ) 0x00 前言 天下武功,唯快不破.但在密码学中则不同.算法越快,越容易破. ...

  3. 散列表(hash table)——算法导论(13)

    1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...

  4. hash表长度优化证明

    hash表冲突的解决方法一般有两个方向: 一个是倾向于空间换时间,使用向量加链表可以最大程度的在节省空间的前提下解决冲突. 另外一个倾向于时间换空间,下面是关于这种思路的一种合适表长度的证明过程: 这 ...

  5. SQL Server-聚焦查询计划Stream Aggregate VS Hash Match Aggregate(二十)

    前言 之前系列中在查询计划中一直出现Stream Aggregate,当时也只是做了基本了解,对于查询计划中出现的操作,我们都需要去详细研究下,只有这样才能对查询计划执行的每一步操作都了如指掌,所以才 ...

  6. C# salt+hash 加密

    一.先明确几个基本概念 1.伪随机数:pseudo-random number generators ,简称为:PRNGs,是计算机利用一定的算法来产生的.伪随机数并不是假随机 数,这里的" ...

  7. SQL 提示介绍 hash/merge/concat union

    查询提示一直是个很有争议的东西,因为他影响了sql server 自己选择执行计划.很多人在问是否应该使用查询提示的时候一般会被告知慎用或不要使用...但是个人认为善用提示在不修改语句的条件下,是常用 ...

  8. 对一致性Hash算法,Java代码实现的深入研究

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  9. 巧用location.hash保存页面状态

    在我们的项目中,有大量ajax查询表单+结果列表的页面,由于查询结果是ajax返回的,当用户点击列表的某一项进入详情页之后,再点击浏览器回退按钮返回ajax查询页面,这时大家都知道查询页面的表单和结果 ...

  10. redis数据结构详解之Hash(四)

    序言 Hash数据结构累似c#中的dictionary,大家对数组应该比较了解,数组是通过索引快速定位到指定元素的,无论是访问数组的第一个元素还是最后一个元素,所耗费的时间都是一样的,但是数组中的索引 ...

随机推荐

  1. 安装Android Studio遇到的问题

    1. 学习视频 视频链接:https://www.bilibili.com/video/BV1jW411375J?p=2 2. Android Studio1.5.1的下载地址: http://www ...

  2. (解决)easypoi图片导出只占用一个单元格

    @ 目录 前提 依赖环境 问题原因 解决方案 重写jar中的方法 原理 前提 本解决方案来源于网络,因解决自己需求,因此自行记录起来,如有侵权请联系我. 依赖环境 easypoi--依赖版本3.1.0 ...

  3. nodejs事件和事件循环详解

    目录 简介 nodejs中的事件循环 phase详解 timers pending callbacks idle, prepare poll轮询 check close callbacks setTi ...

  4. 【Flutter】容器类组件之剪裁

    前言 Flutter中提供了一些剪裁函数,用于对组件进行剪裁. 剪裁Widget 作用 ClipOval 子组件为正方形时剪裁为内贴圆形,为矩形时,剪裁为内贴椭圆 ClipRRect 将子组件剪裁为圆 ...

  5. .NET Core部署到linux(CentOS)最全解决方案,常规篇

    本文为大家介绍使用 .NET Core部署到Linux服务器的方法,通过本文你将了解到Linux在虚拟机下的安装.Xshell,Xftp的使用方法.git在linux下的交互使用以及.net core ...

  6. kubernets之statefulset资源

    一  了解Statefulset 1.1  对比statefulset与RS以及RC的区别以及相同点 Statefulset是有状态的,而RC以及RS等是没有状态的 Statefulset是有序的,拥 ...

  7. px转rem的填坑之路

    这是要为一个vue项目做自适应,设计稿是1920*1080的,要适应各种手机.ipad.3840*2160的超大屏,所以就选择了rem,包用的是 postcss-pxtorem 在适配的时候遇到了很多 ...

  8. 1.5V升3.3V芯片电路图,稳压3.3V供电MCU模块等

    干电池1.5V可以升到3.3V,通过PW5100干电池升压IC,于外围3个元件:2个电容和一个电感即可组成1.5V升3.3V的电路系统. 干电池属于低能量的电池产品,不过一般使用到干电池的产品也是输出 ...

  9. 理解Go的多态实现

    总结两点: 在Go中,定义一个interface类型,该类型说明了它有哪些方法.使用时,在函数中,将该interface类型作为函数的形参,任意一个实现了interface类型的实参都能作为该inte ...

  10. JSAAS BPM快速开发平台-企业管理软件,专属你的企业管家

    前言: 2020年,企业该如何去选择合适的信息化规划管理软件,基于目前社会软件杂乱无章,选择企业业务贴近的管理软件,甚是困难,市场上一些大品牌公司的产品,定位高,价格高,扩展难,等等一系列的问题,对于 ...