KMP算法与next数组

本文详细介绍了KMP(Knuth-Morris-Pratt)算法中的next数组概念及其计算方法,包括递归法求解next数组的过程。KMP算法用于文本串中模式串的匹配,通过next数组实现高效回溯,避免不必要的字符比较。文章还讨论了next数组在匹配过程中的作用,以及如何利用nextval数组进一步优化匹配效率,提高查找模式串在文本串中出现次数的计算速度。

next数组

next[i]表示使子串s[0···i]的前缀s[0···k]等于后缀s[i-k···i]的最大的k(前缀和后缀可以重叠,但不能是s[0···k]本身,当找不到相等的前后缀时令next[i]=-1(即next[i]是所求最长相等前后缀中前缀最后一位的下标)

用递归法求解next[i]:

void getNext(char s[],int len){//getNext求解长度为len的字符串s的next数组
    int j=-1;
    next[0]=-1;//初始化j=next[0]=-1
    for(int i=1;i<len;i++){//求解next[1]~next[len-1]
        while(j!=-1 && s[i]!=s[j+1]){//注意是&&
            j=next[j];//反复令j=next[j]
        }//知道j退回-1或s[i]==s[j+1]
        if(s[i]==s[j+1]){//如果s[i]==s[j+1]
            j++;//next[i]=j+1,先令j指向这个位置
        }
        next[i]=j;//令next[i]=j;
    }
}

KMP算法中的next数组含义

(i指向text的当前欲比较位,j指向pattern中当前已匹配的最后位)

next数组的含义是当j+1位失败时,j应该退回的位置

KMP算法

bool KMP(char text[], char pattern[]) {//判断pattern是否为text的子串
    int n = strlen(text), m = strlen(pattern);//求出字符串长度
    getNext(pattern, m);//求出pattern的next数组
    int j = -1;//初始化为-1,表示当前还没有任意一位被匹配
    for (int i = 0; i < n; i++) {//试图匹配text[i]
        while (j != -1 && text[i] != pattern[j + 1]) {
            j = next[j];//不断回退,直到j回到-1或text[i]==pattern[j+1]
        }
        if (text[i] == pattern[j + 1]) {
            j++;//text[i]与pattern[j+1]匹配成功,令j加一
        }
        if (j == m - 1) {//pattern完全匹配,说明pattern是text的子串
            return true;
        }
    }
    return false;//当执行玩text还未匹配成功时,说明pattern不是text的子串
}

统计文本串中模式串出现的次数

int KMP_num(char text[],char pattern[]){//统计pattern在text中出现的次数
    int n=strlen(text),m=strlen(pattern);//字符串长度
    getNext(pattern,m);//计算pattern的next数组
    int ans=0,j=-1;//ans表示成功匹配次数,并初始化j为-1
    for(int i=0;i<n;i++){//试图匹配text[i]
        while(j!=-1&&text[i]!=pattern[j+1]){
            j=next[j];//不断回退,直到j回到-1或text[i]==pattern[j+1]
        }
        if(text[i]==pattern[j+1]){
            j++;//text[i]与pattern[j+1]匹配成功,令j加一
        }
        if(j==m-1){//pattern完全匹配,说明pattern是text的子串
            ans++;//成功匹配次数加1
            j=next[j];//让j回退到next[j]继续匹配
        }
    }
    return ans;//返回成功匹配的次数
}

对KMP算法的优化

j回退无意义的问题出在pattern[j+1]==pattern[next[j]+1]上

nextval数组:不再是最长相等前后缀的含义,却让失配时处理最优

当模式串pattern的i+1位发生失配时,i应当退回的最佳位置

int KMP1_num(char text[],char pattern[]){//统计pattern在text中出现的次数
    int n=strlen(text),m=strlen(pattern);//字符串长度
    getNext(pattern,m);//计算pattern的next数组
    int ans=0,j=-1;//ans表示成功匹配次数,并初始化j为-1
    for(int i=0;i<n;i++){//试图匹配text[i]
        while(j!=-1&&text[i]!=pattern[j+1]){
            j=next[j];//不断回退,直到j回到-1或text[i]==pattern[j+1]
        }
        if(text[i]==pattern[j+1]){
            j++;//text[i]与pattern[j+1]匹配成功,令j加一
        }
        if(j==m-1){//pattern完全匹配,说明pattern是text的子串
            ans++;//成功匹配次数加1
            j=next[j];//让j回退到next[j]继续匹配
        }
    }
    return ans;//返回成功匹配的次数
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值