KMP算法学习笔记

KMP算法的关键是主串不回溯。

KMP算法学习笔记_第1张图片

每当主串和模式串匹配,i、j各自前进一格。这个和暴力匹配是一样的。
出现不匹配的时候,因为不让主串回溯了,代之以右滑模式串到一个指定的位置。数组next[]表示模式串的某一位置出现不匹配时,应该右滑到哪个位置。
next[]中取-1表示即使退回到第一个值也无法匹配。所以,这时候也应该各自前进一格。
这样一来,由于主串不回溯,对于长为m的主串来说,至少匹配了m次。
每次右滑,额外带来一次匹配,但右滑的距离无法超过总距离。所以至多匹配了2m次。
也就是说,时间复杂度为O(m)。
让我们手动跑一下……
KMP算法学习笔记_第2张图片
KMP算法学习笔记_第3张图片
KMP算法学习笔记_第4张图片
KMP算法学习笔记_第5张图片
KMP算法学习笔记_第6张图片
大概就是这么个原理。

代码如下:

//kmp算法
int kmp(string s1,string s2)
{
    int*next=new int[s2.size()];
    getnext(s2,next);
    int i=0, j = 0;
    while (i<int(s1.size()) && j<int(s2.size()))
    {
        if (j==-1||s1[i]==s2[j])
        {
            i++; j++;
        }
        else
        {
            j = next[j];
        }
    }
    if (j==s2.size())
    {
        return i - s2.size();
    }
    else
    {
        return -1;
    }
}

next[]的求法:
如果连第一个值都无法与主串匹配,那显然应该用模式串的第一个值和主串的下一个位置比较。令next[0]=-1。
next[]的其他值按以下步骤递推而来:
若模式串s中下标为j的元素对应的next[j]为k,且s[j]=s[k],那么令next[j+1]=k+1。(这是因为,next[j]=k意味着s最开头0~k-1的元素与位于j前面的j-k~j-1元素一一相等,所以可以从k开始比较。如果s[j]=s[k],意味着位于0~k的元素与位于j-k~j的元素相等,也就是next[j+1]=k+1)
若s[j]不等于s[k],令k=next[k]。(如果j-k~j-1无法与最前面的k+1个元素匹配,也就是说我们没办法找到最长的这个串了。但是我们可以找到次长的。k肯定比j小,所以next[k]已经计算出来了。这里一边计算后面的结果一边利用前面的结果。)

其实这些就够了,不过它还能更快。如果不仅仅是s[j]==s[k],而且连s[j+1]==s[k+1]也成立的话……那么s[j+1]不匹配的时候就没必要跳到s[k+1]去了。反正s[k+1]肯定也不匹配,那我们可以直接跳到next[k+1]去。不过这只是有可能减少右滑模式串的次数,总的匹配次数依然是m~2m,时间复杂度也没有变化。
手动跑一下的话比较直观吧。就是省略了比较前两个a。
KMP算法学习笔记_第7张图片
KMP算法学习笔记_第8张图片
KMP算法学习笔记_第9张图片
代码如下:

//取得模式串的next[]
void getnext(string s2, int next[])
{
    unsigned int j = 0;
    int k = -1;
    next[j] = k;
    while (jif (k==-1 || s2[j]==s2[k])
        {
            j++; k++;
            if (s2[j]==s2[k])
            {
                next[j] = next[k];
            }
            else
            {
                next[j] = k;
            }
        }
        else
        {
            k = next[k];
        }
    }
}

最后测试一下。

int main()
{
    string s1 = "Across the Great Wall we can reach every corner in the world.";
    string s2;
    cout << s1 << endl;
    cin >> s2 ;
    cout<cout << s1.substr(kmp(s1,s2),s2.size()) << endl;
    system("pause");
    return 0;
}

KMP算法学习笔记_第10张图片

你可能感兴趣的:(KMP)