字符串匹配(Hash)

 俗话说:

字符串问题只有一种做法----Hash;Hash Hash

字符串匹配【KMP模板】

题目描述

给定两个由小写字母构成的字符串 L 和 S 。
请你从左到右,找出子串 L 在母串 S 中每次出现的开始位置(匹配位置)。

输入格式

第一行:给一个全由小写字母构成的母串 S(0<S的长度≤1000000);
第二行:给一个全由小写字母构成的子串 L(0<L的长度≤S的长度)。

输出格式

按升序输出一行一个整数,分别表示子串 L 在母串 S 中每次出现的开始位置。
如果子串 L 在母串 S 中没有出现,则输出“NO”。

样例数据 1

输入  [复制]

yuabcierabcde 
abc

输出


9

样例数据 2

输入  [复制]

abcdefg 
abcdefu

输出

NO

备注

【样例1说明】
从第3个位置起,第一次匹配;
从第9个位置起,第二次匹配。

用Hash写kmp模板......

扫描二维码关注公众号,回复: 2914273 查看本文章

字符串匹配主要是求Hash前缀

举个例子

'abcde'

Hash[1]=a  Hash[2]=Hash[1]*31+b  Hash[3]=Hash[2]*31+c...

那我们要去'cd'的Hash值

就可以Hash[4]-Hash[2]*31*31

于是我用map+unsigned long long 来存

unsigned long long 可以不用取模, 大于2^64自动%2^64 而且非常快

typedef unsigned long long ULL;
map<int,ULL> Hash;
   //求a的Hash前缀
     for(int i=1;i<=s1;i++){
		Hash[i]=Hash[i-1]*31+a[i];
	}

开始匹配

    //s1,s2为长度,j为当前匹配的末尾,i是开头
    //与普通前缀和一样是Hash[i-1]
    //mul[s2]=31^s2
    for(int i=1;i<=s1-s2+1;i++){
		int j=i+s2-1;
		ULL x=Hash[j]-Hash[i-1]*mul[s2];
		if(x==sum) cout<<i<<endl,bj=1;
	}

 预处理mul

    mul[1]=1;
    for(int i=31;i<=s2;i++) 
        mul[i]=mul[i-1]*31;

 时间复杂度 O(n)

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/81915301