KMP算法

KMP 算法

 

简介: KMP算法是一种能够在线性时间内求出一个串在另一个串的所有匹配位置.

核心: KMP算法中失配数组 F[ i ] 的求解. F[i] 数组表示主串S中以第i个字符(S[i-1])为尾的后缀与模式串T的前缀的最长公共部分.

KMP本质其实是看主串S中每个i位置的后缀最多能与T的多长的前缀匹配的算法. 也就是前缀匹配后缀的算法. 进行模式匹配只是一个附加的结果. 比如说:F[i] ==x 表示i位置的模式串T的0到i-1字符串的后缀能与T的0到x-1匹配. 也就是说当T[i] 与 S[j] 不匹配的时候, 就取用T[F[i]] == T[x] 与S[j] 匹配看看是否匹配.

KMP这种前缀后缀的思想要好好体会~ 是学习后面的字符串算法的基础!

注意: 蓝书上给的是MP算法 均摊复杂度是线性的. KMP需要失配指针一次性指到最前面, 而不是MP中的一次一次的跳(类似于并查集的路径压缩).

/*************************MP模板****************************/
char T[1000];//待匹配串
char P[100];//模板串
 
//失配指针,记住这里f要比P多一位
//因为P到m-1即可,但是f还要计算出m的失配指针
int f[101];
 
void getFail(char *P, int *f)
{
    int m = strlen(P);
    f[0] = f[1] = 0;
    for(int i = 1; i < m; i++)//虽然字符串是0到m-1,但是要求出f[m]的值
    {
        int j = f[i];
        while(j && P[i] != P[j]) j = f[j];
        f[i + 1] = P[i] == P[j] ? j + 1 : 0;
    }
}

void find(char *T, char *P, int *f) //找到所有匹配点
{
    int n = strlen(T);
    int m = strlen(P);
    int j = 0;
    for(int i = 0; i < n; i++)
    {
        while(j && T[i] != P[j]) j = f[j];
        if(T[i] == P[j]) j++;
        if(j == m) printf("%d\n", i - m + 1);//就算j到m了,也用f[m]继续匹配
    }
}
/*************************MP模板****************************/
 
 
/*************************KMP模板****************************/
char T[1000];//待匹配串
char P[100];//模板串
int f[101];//优化后的失配指针,记住这里f要比P多一位,因为P到m-1即可,但是f还要计算出m的失配指针
int f2[101];//f2用来保存KM指针,是为优化f的失配指针,f保存的是优化之后的失配指针
void getFail(char *P, int *f)
{
    int m = strlen(P);
    f[0] = f[1] = 0;
    f2[0]=f2[1]=0;
    for(int i = 1; i < m; i++)
    {
        int j = f2[i];
        while(j && P[i] != P[j] ) j = f2[j];
        f2[i+1] = f[i + 1] = (P[i] == P[j]) ? j + 1 : 0;
 
        //既然i+1的失配位置指向j+1,但是P[i+1]和P[j+1]的内容是相同的
        //所以就算指针从i+1跳到j+1去,还是不能匹配,所以f[i+1]直接=f[j+1]
        if(f[i+1]==j+1 && P[i+1]==P[j+1]) f[i+1]=f[j+1];
    }
}

void find(char *T, char *P, int *f) //找到所有匹配点
{
    int n = strlen(T);
    int m = strlen(P);
    int j = 0;
    for(int i = 0; i < n; i++)
    {
        while(j && T[i] != P[j]) j = f[j];
        if(T[i] == P[j]) j++;
        if(j == m) printf("%d\n", i - m + 1);
    }
}
/*************************KMP模板****************************/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值