/*新的看 毛 片算法
关于字符串匹配
1:暴力匹配 wcy的代码
匹配成功就是匹配一个对齐位置 从左向后 扫一遍 O(m)<=复杂度<=O(mn)
实现:
int stupid1(char *t,char *s){
int size_t = strlen(t),i = 1; //每个串后面有\n 作为一个flag
int size_s = strlen(s) j = 1; // i j 匹配位置下标 j也同样可以理解成功匹配次数
while(j < m || i <n) //s 从1 扫到 m 判断位置(i - j,i - j + m)
if(t[i] == s[j]){s++;t++;} //成功匹配下标同时加
else{i -= j - 1;j = 1} // 出现不匹配 下表j 清零 下表i减掉已经匹配的然后 +1 往下走
return i - j; //就在这样一个i-j的位置 不合法会出现 i-j > n-m
}
int stupid2(char *t,char *s){
int size_t = strlen(t), i = 0; //s[0] 对t[i]
int size_s = strlen(s),j; // s[j]对应从t[i+j] 匹配方式j对应s从1扫到m;i对应 t从i扫到i+m;
for(int i = 1;n <= n - m + 1;i++){ //注意要加1
for(int j = 1;j <= m;j++)
if(t[i+j] != s[j]) break; //失配了 直接break
if(m <= j) break; // 找到了
}
return i; //直接返回i就好
}
局部匹配用的时间太长了! 期望复杂度大概到O(n)
2.KMP:最坏也是线性时间
暴力速度低的原因:移动的时候只移动一个位置 每个匹配串都要匹配一波前缀
我的同学swj god发现:每次匹配前面一部分都被匹配了,消耗了大部分时间,而每一次匹配没必要反复进行
暴力算法中的每一个匹配过程(t[i]s[j])中 s的子串和前缀完全相同 后面的匹配可以利用
考察失败的匹配 我们仍然获得了他之前成功的子匹配 wcy写的暴力stupid算法没有注意到
于是swj god由记忆化的想法 给了wcy一个更好的想法 :
t[i]和s[j] 获得匹配时 我们没有必要匹配t[i-j] s[j]前面的位置 也就是我们直接匹配新的ij就熊
相对于当前的比对位置 我们首次失败的时候完全没必要像wcy一样一点一点的移动 只要有子串中有一个于开头相同的字符我们可以
大方的直接移到这个位置 然后开始匹配就好 swj god 直接给出了这个方法的预处理手段
首次失败与t[i] 与 s[j] 失配的时候 断言:失配后下一个字符和原文本串无关
因为我们将文本串分为:前缀 已匹配部分 失配字符 后缀
而已匹配部分可以由匹配串 的匹配代替
但是下一个字符的顶替最多就m中
于是就直接有了next数组也就是查询表的构造方法 我们在s[j] 失配的时候我们将j换成next[j]
实际上就是一个预处理方案数组
栗子:c h i n c h i l l a
1 2 3 4 5 6 7 8 9 10
-1 0 0 0 0 1 2 3 0 0
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define INF 1e9+7
using namespace std;
const int N = 10010,M = 110;
int KMP(*t,*s);
int buildNext(*s);
/*inline int read(){
int y = 1,ans;
char c = getchar();
while(c < '0' || c > '9')}{
if(c == '-') y = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
ans = ans * 10 + c - '0';
c = getchar();
}
return ans*y;
}
inline void write(int x){
if(x < 0){
x = ~x + 1;
purchar('-');
}
if(c > 9){
write(x / 10);
}
putchar(x & 10 +'0');
}*/
int main(){
char t[N],s[M];
int n;
cin>>t>>n;
for(int i = 1;i <= n;i++){
cin>>s;
KMP(t,s);
}
return 0;
}
//wcy 垃圾暴力1改进
int KMP(char *t,char *s){
int *next = buildNext(s); //预处理构造next
int n = strlen(t),i = 0; //同暴力1
int m = strlen(s),j = 0;
while(j < m && i < n){
if(j < 0 || t[i] == s[j]){
i++;j++;
}
else{
j = next[j]; //只需要取出next的所包含的信息就行 不需要退回
}
}
return i - j;
}