俗话说:
字符串问题只有一种做法----Hash;Hash Hash
字符串匹配【KMP模板】
题目描述
给定两个由小写字母构成的字符串 L 和 S 。
请你从左到右,找出子串 L 在母串 S 中每次出现的开始位置(匹配位置)。输入格式
第一行:给一个全由小写字母构成的母串 S(0<S的长度≤1000000);
第二行:给一个全由小写字母构成的子串 L(0<L的长度≤S的长度)。输出格式
按升序输出一行一个整数,分别表示子串 L 在母串 S 中每次出现的开始位置。
如果子串 L 在母串 S 中没有出现,则输出“NO”。样例数据 1
输入 [复制]
yuabcierabcde
abc输出
3
9样例数据 2
输入 [复制]
abcdefg
abcdefu输出
NO备注
【样例1说明】
从第3个位置起,第一次匹配;
从第9个位置起,第二次匹配。
用Hash写kmp模板......
字符串匹配主要是求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)