kmp1.1

/*新的看 毛 片算法 
关于字符串匹配
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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值