HASH意为(散列),是OI的常用算法。

我们常用哈希的原因是,hash可以快速(一般来说是O(段长))的求出一个子段的hash值,然后就可以快速的判断两个串是否相同。

今天先讲string类的hash。


可以发现,与一个string有关的HASH值不仅仅跟每个字符的个数有关,还和字符的位子有关。

通过简单的思考,我们可以构造如图的模型:

写一个比较正常的hash模板吧

const int EE = 97;
const int MOD = 100000007;
int HASH(string p)
{
   int E = 1;
   int ret = 0;
   int tl = p.size();
   for (int i=0;i<tl;i++)
      ret += E*p[i], E *= EE;
   return ret;
}
题目来了:

KMP问题

题目描述

如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。

输入输出格式

输入格式:

第一行为一个字符串,即为s1

第二行为一个字符串,即为s2

输出格式:

一行包含一个整数,表示s2在s1中出现的位置的个数

输入输出样例

输入样例#1:

ABABABC
ABA
输出样例#1:

2

说明

时空限制:1000ms,128M

数据规模:

设s1长度为N,s2长度为M

对于30%的数据:N<=15,M<=5

对于70%的数据:N<=10000,M<=100

对于100%的数据:N<=1000000,M<=1000000


思路

首先说明:此题正解为KMP,不为hash。如果想知道KMP算法,请百度一下。

但是我们学的可是“hash”呀,不能直接预处理,如果直接预处理的话,时间为O(n*m),炸掉。

我们就可以递推:

  "已知长度为m的序列a[1]...a[m],现在已知"a[1]...a[m]"的hash值为K,欲求a[2]...a[m+1]的hash值。"

我首先想到的是乘法逆元,但还有其他的更简便的方法。

可以这一样想:"改变EE的赋值方式,反过来赋值,这样的话可以直接删去第一个'a[1]*EE^(m-1)',再乘一个'EE',往后再移一位,再加上一个a[m+1]."

那么,转移方程也很容易写了,为HASH[i]=(HASH[i-1]-a[i-2]*E[1]%M+M)%M*EE%M+a[i-2+m];(HASH[i]表示a[i-1]到a[i+m-2]的hash值。

另附代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,k,len1,len2;
int next1[1000001];
char s1[1000001];
char s2[1000001];
long long HASH[1000001];
long long E[1000001],M=1234567898765;

long long EE = 97;

int init()
{
    long long Key=0;
    int ans=0;
    memset(E,0,sizeof(E));
    memset(HASH,0,sizeof(HASH));
    E[len2]=1;
    for (int i=len2-1;i>=1;i--)
        E[i]=E[i+1]*EE%M;
    for (int i=1;i<=len2;i++)
        HASH[1]=(HASH[1]+E[i]*(s1[i-1]))%M;
    for (int i=1;i<=len2;i++)
        Key=(Key+E[i]*(s2[i-1]))%M;
    if (HASH[1]==Key) ans++;
    for (int i=2;i<=len1-len2+1;i++)
    {
        HASH[i]=(HASH[i-1]-s1[i-2]*E[1]%M+M)%M*EE%M+s1[i-2+len2];
        if (HASH[i]==Key) ans++;
    }
    printf("%d\n",ans);
}
int main(){
    scanf("%s",s1) ;
    scanf("%s",s2) ;
    len1=strlen(s1);
    len2=strlen(s2);
    init();
    return 0;
}

详解HASH(字符串哈希)的更多相关文章

  1. 多表连接的三种方式详解 hash join、merge join、 nested loop

    在多表联合查询的时候,如果我们查看它的执行计划,就会发现里面有多表之间的连接方式.多表之间的连接有三种方式:Nested Loops,Hash Join 和 Sort Merge Join.具体适用哪 ...

  2. HASH 字符串哈希 映射转化

    哈希HASH的本质思想类似于映射.离散化. 哈希,通过给不同字符赋不同的值.并且钦定一个进制K和模数,从而实现一个字符串到一个模意义下的K进制数上. 它的主要目的是判重,用于$DFS$.$BFS$判重 ...

  3. 详解JAVA字符串类型switch的底层原理

    基础 我们现在使用的Java的版本,基本上是都支持String类型的.当然除了String类型,还有int.char.byte.short.enum等等也都是支持的.然而在其底部实现中,还是基于 整型 ...

  4. 数据结构作业——hash(字符串哈希)

    Hash Description 给定长度为 n ( n<=1000000)的字符串,字符串仅由小写字母的前 m ( m<=6) 个字符组成,请你计算出共有多少长度为 k( k<=6 ...

  5. 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP

    在多表联合查询的时候,如果我们查看它的执行计划,就会发现里面有多表之间的连接方式. 之前打算在sqlplus中用执行计划的,但是格式看起来有点乱,就用Toad 做了3个截图. 从3张图里我们看到了几点 ...

  6. 【Python】Java程序员学习Python(七)— 文本类详解(字符串、str)

    如果一个女孩子喜欢看龙猫,那么请珍惜她,呵护她 任何一门语言,字符串总是最基本也是最需要掌握的一个变量,想想入门的Hello World,输出的就是字符串. 官方文档:https://docs.pyt ...

  7. boost::algorithm用法详解之字符串关系判断

    http://blog.csdn.net/qingzai_/article/details/44417937 下面先列举几个常用的: #define i_end_with boost::iends_w ...

  8. Java String类详解

    Java String类详解 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 类结构: public final ...

  9. SqlHelper帮助类_上(SQLServer数据库含Connection详解)

    在操作数据库时,经常会用到自己封装的SqlHelper.这里主要对SQLServer数据库的Sqlhelper,主要用于在同一个连接中完成CRUD! 一.ADO.NET中的Connection详解: ...

随机推荐

  1. 六、Zabbix-自动分组

    一.配置Zabbix server 1.创建主机组 (2)配置—>主机群组—>创建主机群组 (2)Next Step (3)可以看到新添加的主机组 2.添加自动分组动作 配置—>动作 ...

  2. glide使用总结

    1 glide是什么 glide是一个图片加载和缓存库. 2 glide的使用 第一,添加依赖 implementation 'com.github.bumptech.glide:glide:4.5. ...

  3. P1076寻宝

    ---恢复内容开始--- 这是2012noip普及组的一个模拟题,第一次得了50,看了题解后剪枝拿到100. N层楼,m个房间,逆时针排序.每个房间有一个指示牌,也可能有楼梯,找到第(上楼的第一个房间 ...

  4. Vim实用技巧(一)

    vim 命令按键规定 标记 含义 x 按一次 x dw 按一次 d, w dap 按一次 d, a, p 同时按 和 n g<C-]> 按 g, 然后同时按 和 ] <C-=> ...

  5. babel的初步了解

    前段时间开始研究ast,然后慢慢的顺便把babel都研究了,至于ast稍后的时间会写一篇介绍性博客专门介绍ast,本博客先介绍一下babel的基本知识点. 背景: 由于现在前端出现了很多非es5的语法 ...

  6. C++关于erase的复杂度(转载)

    被这个问题困扰了很多次,有必要整理一下. 当然最好的参考资料就是http://www.cplusplus.com/reference/set/set/erase/ 里的Complexcity部分了,但 ...

  7. Educational Codeforces Round 72 (Rated for Div. 2) Solution

    传送门 A. Creating a Character 设读入的数据分别为 $a,b,c$ 对于一种合法的分配,设分了 $x$ 给 $a$ 那么有 $a+x>b+(c-x)$,整理得到 $x&g ...

  8. angular 示例项目

    cnpm install 环境安装好后,快速创建一个新项目,如在D盘下新建一个angularProject项目,只要在本地目录下 ng new angularProject angularProjec ...

  9. C++------流星雨

    用C++实现模拟数字.字母流星雨,其主要用到链表.win32编程基础. demo实例: // DataRainDemo.cpp : 定义应用程序的入口点. // #include "stda ...

  10. 锋利的jQuery ——jQuery选择器(二)

    一.jQuery选择器 1)CSS选择器 CSS选择器有:1>标签选择器  E{CSS规则} 2>ID选择器   #ID{CSS规则} 3>类选择器  E.className{CSS ...