给你两个由小写英文字母组成字符串s,t。如果s[i...i+|t|-1] = t (|t|表示t的长度),则认为s[i...i+|t|-1] 是t的相等串。现在有q次询问,每次询问你s[L..R]中有多少个不同位置的t的相等串。
Input
第一行输入三个整数n,m,q,表示s,t的长度和询问次数。(1 <= n,m <= 1000 , 1 <= q <= 1000000)。
第二三行分别给出s,t。
接下来q行,每行输入L,R,表示所要查询的区间。(1 <= L <= R <= n)
Output
输出q行,表示每次查询的结果。
Examples
Input1
10 3 4 codezzzces zzz 1 3 3 10 5 6 5 7
Output1
0 1 0 1
Input2
15 2 3 abacabadabacaba ba 1 15 3 4 2 14
Output2
4 0 3
Input3
3 5 2 aaa baaab 1 3 1 1
Output3
0 0
这道题目,可以使用KMP来做,也可以使用STL来做。
1.STL 解法
就是我先将第二个字符串 在第一个字符串的位置都找出来存到一个数组中去,然后在一堆询问中,遍历数组去找一共出现了几次,时间相比KMP要少很多。但是 有一些KMP的题目 是不适合使用 STL 去FIND的,很有可能会超时,有的题目使用STL 就会更高效 简单。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<vector>
#include<string.h>
#include<bits/stdc++.h>
const int maxn=1000005;
using namespace std;
int main()
{
std::ios::sync_with_stdio(false);
vector<int>ans;
string s,t;
int len;
int len2;
int q;
cin>>len>>len2>>q;
cin>>s>>t;
size_t found=s.find(t);
while(found!=string::npos)
{
ans.push_back(found+1);
found=s.find(t,found+1);
}
int l,r;
while(q--)
{
int k=0;
cin>>l>>r;
if(r-l+1>=len2)
for(int i=0;i<ans.size();i++)
{
if(l<=ans[i]&&r>=ans[i]+len2-1)
k++;
}
cout<<k<<endl;
}
return 0;
}
2.KMP
怎么感觉 KMP 写的比STL 简单许多,但是时间 时间上STL快一些
就是将KMP 匹配范围更新为 题目所给的 l,r,我们在这段区域内匹配字符串 就可以了。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<vector>
#include<string.h>
#include<bits/stdc++.h>
const int maxn=1000005;
using namespace std;
int len1,len2,q;
string s,t;
int nex[maxn];
void getnex(string t)
{
int i=0;
int j=-1;
nex[0]=-1;
while(i<len2)
{
if(j==-1||t[i]==t[j])
{
i++;
j++;
nex[i]=j;
}
else
j=nex[j];
}
}
int kmp(int l,int r)
{
int k=0;
int i=l-1;
int j=0;
while(i<r)
{
if(j==-1||s[i]==t[j])
{
i++;
j++;
}
else
j=nex[j];
if(j>=len2)
{
k++;
j=nex[j];
}
}
return k;
}
int main()
{
std::ios::sync_with_stdio(false);
cin>>len1>>len2>>q>>s>>t;
getnex(t);
while(q--)
{
int l,r;
cin>>l>>r;
cout<<kmp(l,r)<<endl;
}
return 0;
}