kmp

   在暴力匹配两个字符串时,如果匹配失败,文本串跳到刚开始匹配的下一位置,模式串跳到开头。

暴力匹配具体步骤:

  1. 如果匹配成功,则++i,++j,继续匹配下一字符;
  2. 如果匹配失败,i=i-(j-1),j=0,即i回溯,j置0(从头再来)
int violentMatch(const string& s,const string& p)
{
    int sLen=s.size();
    int pLen=p.size();
    int i=0,j=0;
    while(i<sLen&&j<pLen)
    {
        if(s[i]==p[j])
        {
            ++i;
            ++j;
        }
        else
        {
            i=i-j+1;
            j=0;
        }
    }
    return j==pLen?i-j:0;
}

  为了减少时间复杂度,在kmp算法中,匹配失败时文本串不动,移动模式串来进行下次匹配,模式串的移动位置靠next数组来决定。

  next 数组各值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。例如如果next [j] = k,代表j 之前的字符串中有最大长度为k 的相同前缀后缀。此也意味着在某个字符失配时,该字符对应的next 值会告诉你下一步匹配中,模式串应该跳到哪个位置(跳到next [j] 的位置)。如果next [j] 等于0或-1,则跳到模式串的开头字符,若next [j] = k 且 k > 0,代表下次匹配跳到j 之前的某个字符,而不是跳到开头,且具体跳过了k 个字符。

kmp具体步骤:

  1. 如果j==-1(模式串跳到第一个字符)或 当前位置模式串和文本串匹配成功:则++i,++j;
  2. 如果next[j]>0,则模式串跳到以j结尾字符串的最长前缀和最长后缀相等的位置,即j=next[j]。
#include <iostream>
#include <vector>
using namespace std;

class Kmp
{
private:
    vector<int> next;//next[i],以i结尾(不包含i)的最长前缀和后缀相等的值
private:
    void getNext(const string& p)//求模式串的next数组
    {
        int pLen=p.size();
        next.resize(pLen,0);
        next[0]=-1;
        next[1]=0;
        int flag=0;
        for(int i=2;i<pLen;)
        {
            if(p[flag]==p[i-1])
                next[i++]=++flag;
            else if(flag>0)
                flag=next[flag];
            else
                next[i++]=0;
        }
        return ;
    }
public:
    int kmp(const string& s,const string& p)
    {
        getNext(p);
        int i=0,j=0;
        int sLen=s.size(),pLen=p.size();
        while(i<sLen&&j<pLen)
        {
            if(s[i]==p[j])
            {
                ++i;
                ++j;
            }
            else if(next[j]==-1)//j移动到模式串的第一个字符,即j==0
            {
                ++i;
            }
            else
            {
                j=next[j];
            }
        }
        //与下列等效
        #if 0
        while(i<sLen&&j<pLen)
        {
            if(j==-1||s[i]==p[j])
            {
                ++i;
                ++j;
            }
            else
            {
                j=next[j];
            }
        }
        #endif // 0
        return j==pLen?i-j:0;
    }
};
int main()
{
    Kmp k;
    cout<<k.kmp("BBC ABCDAB ABCDABCDABDE","ABCDABD")<<endl;
    return 0;
}

 

posted on 2019-03-16 22:42  tianzeng  阅读(189)  评论(0编辑  收藏  举报

导航