基本上是kmp,不过比较的时候有个技巧
废话不多说,先上代码
int Next[1000008];
void getNext(string s) {
int len = (int)s.size();
//VI Next(len);
Next[0] = -1;
int i=0, j=-1;
while (i<len) {
if (j==-1 || s[i]==s[j]) {
Next[i] = j;
i++; j++;
}
else
j = Next[j];
}
//return Next;
}
int kmp(string ori, string pat) {
int cnt = 0;
getNext(pat);
//VI Next = getNext(pat);
int j = 0;
for (int i=0; i<SZ(ori); i++) {
while (i<SZ(ori) && j<SZ(pat)) {
if (ori[i] == pat[j]) {
j++; i++;
}
else {
if (j == 0)
++i;
else
j = Next[j-1] + 1;
}
}
if (j == SZ(pat)) {
cnt++;
//cout<<"i: "<<i<<endl;
j = Next[j-1]+1;
i = i-(SZ(pat)-j);
}
}
return cnt;
}
int main() {
ios::sync_with_stdio(false);
//freopen("in.in","r",stdin);
//int cnt;
int t;
cin>>t;
string ori, pat;
while(t--) {
cin>>pat>>ori;
cout<<kmp(ori,pat)<<endl;
}
return 0;
}
hihoCoder这个语言选择。。。啥时候能记忆一下用户常选语言【老CE也是伤不起啊尼玛】。。。G++版本略老啊。。。。
其实差不多就是个KMP比较!
但是如果你在kmp函数里面每次调用只匹配一次就不对了。。。。
我们来看一个坑爹的case:
ADA ADADADAADA出现了几次呢?3次,起始点index分别是0, 2, 4,发现了吧,那你调用的时候难道是用kmp返回找到的起始index,然后origin串起始点i的下一个点i+1作为匹配的起始点再来一发匹配?如果这样交了就TLE了。。。。
我开始就是这样
int kmp(int ori_start, string ori, string pat) {
// ...
if (found)
return index;
return -1;
}
我很菜,之前一直以为这样写。。。但这样太不机智了。。。
你每次就移动一位,如果遇到了pat 很长很长,但是在ori中匹配了多次的情况,可是每次情况又间隔比较远
pat = WOZHENDESHIJURUOYA
ori = WOZHENDESHIJURUOXXXXXXWOZHENDESHIJURUOYAWOZHENDESHIJURUOXX
这种情况,假设比这长得多,间隔总是匹配着匹配着到最后发现不一样了,然后return -1,移动一位index,非常容易TLE【我也不知道他怎么卡的。。冏】
所以还要利用next数组
还说这种情况
ADA
ADADADA
你看,ADA匹配了第一次后该咋办捏。。。要怎么样才能更快匹配下一次。。。?
对!!就是想办法把ADA直接挪到下一个能更顺利匹配的地方【这个说法好像没啥用。。。】
第一次匹配中,最后一个匹配的都是A,说明那个A以及之前是匹配的,我们回到模式串上一个Next数组中获取到的index,是在D那里,从ori[3]开始,pat[1]开始继续匹配后面的就好了,节约了时间。如果数据比较大会体现得很清楚,总之意思就是移动的位数多了一点而已。。。
其实也不是为了说明白什么,大概自己能看懂留个印记就好啦。。。。