码迷,mamicode.com
首页 > 编程语言 > 详细

KMP 算法简单解释

时间:2019-10-05 22:36:35      阅读:96      评论:0      收藏:0      [点我收藏+]

标签:本质   开始   相同   生成   暴力破解   next   复杂度   class   ++i   

KMP 算法简单解释

? 讲KMP算法,离不开BF,实际上,KMP就是BF升级版,主要流程和BF一样,就是在削除回溯上花了点功夫,利用Next数组来削除

<( ̄︶ ̄)↗[GO!]

1. 先看看BF算法(暴力破解)

int Brute_force_1(const char *S, const char *T)
{
    if (!S || !T)
        return -1;
    int lenS = strlen(S);
    int lenT = strlen(T);
    int i = 0;              //主串下标索引
    int j = 0;              //子串下标索引
    while(i < lenS && j < lenT)
    {
        if (S[i] == T[j])   //如果相等一直继续往下匹配
            ++i,++j;
        else                //不相等i和j开始回溯
        {
            i = i-j+1;
            j = 0;
        }
    }
    if (j == lenT)
        return i - j;
    return -1;
}

? BF算法有几种不同实现,但最终思想都是一样的,以下就是另一个BF实现

int Brute_force_2(const char *S, const char *T)
{
    if (!S || !T)
        return -1;
    int lenS = strlen(S);
    int lenT = strlen(T);
    for (int i = 0; i <= lenS - lenT; ++i)
    {
        int k = i, j = 0;
        while (k < lenS && j < lenT && S[k] == T[j])
        {
            ++j;
            ++k;
        }
        if (j == lenT)
            return i; //说明匹配到了
    }
    return -1;
}

? 你完全可以根据自己的理解写出BF算法,但在这里,为了BF和KMP统一,我们还是采用第一种实现,即容易看出回溯操作的实现

2. Next[]数组

? 事实上,书上的next数组生成算法是经过优化后的算法,比较难懂,但你完全可以按照自己的理解做一个

? 注意:Next[]数组只是在KMP中字符串匹配失败时使用的

void GetNext(int Next[], char *str)
{
    assert(str!=NULL);
    int len = strlen(str);
    if(len>1)Next[0]=0;
//其实Next[0]等于0或者等于-1效果没什么影响,
//因为在KMP中不匹配时判断是不是第一个字符不匹配用用的是j==0;-----if (j==0||Next[j]==0),
    if(len>2)Next[1]=0;
//Next[]等于0时说明需要讲i回溯到子串头的下一个位置(i=i-j+1);
//此时j也回到子串头位置(j=0)
    for(int i=2;i<len;++i)
    {
        for(int j=i-1;j>0;--j)
        {
            if(!strncmp(&str[0],&str[i-j],j))
            {
                Next[i]=j;break;        //找到最大重复子子串(子串中的子串)
//Next[]为其他值则i不变,讲j回溯到Next[j]的位置(j=Next[j])
            }
            else Next[i]=0;
        }
    }
}

? 这个时间复杂度要比书上的方法高很多,但好理解,真实的反映了Next数组的本质。

3.KMP

int KMP(const char *S, const char *T, const int *Next)
{
    if (!S || !T||!Next)
        return -1;
    int lenS = strlen(S);
    int lenT = strlen(T);
    int i = 0;              //主串下标索引
    int j = 0;              //子串下标索引
    while(i < lenS && j < lenT)
    {
        if (S[i] == T[j]) ++i,++j;  //若相等则继续匹配下一个字符
        else        //不相等则回溯
        {
            //(当j==0时,即第一个字符不匹配,和Next[j]==0时事实上与BF算法相同)
            if (j==0||Next[j]==0)
            {
                i = i-j+1;
                j = 0;
            }
            else j = Next[j];//主串i位置不变,讲子串下标索引挪到Next[j]的位置
        }
    }
    if (j == lenT)
        return i - j;
    return -1;
}

? 这个回溯时的操作实际上是把两种情况合成一种,拆开后就是下面的,就是生成next数组那块三种情况

while (i < lenS && j < lenT)
{
    if (S[i] == T[j])
        ++i, ++j;
    else
    {
        if (j == 0)
        {
            ++i; //等价于i = i-0+1;j本身就等于0
        }
        else if (Next[j] == 0)
        {
            i = i - j + 1;
            j = 0;
        }
        else
        {
            j = Next[j];
        }
    }
}

总结

? 其实核心就在与本文第一句话的理解。书上的next数组的生成很难懂,加油理解中。。。(? ?_?)?

KMP 算法简单解释

标签:本质   开始   相同   生成   暴力破解   next   复杂度   class   ++i   

原文地址:https://www.cnblogs.com/starrys/p/11625840.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!