KMP算法

KMP是什么?

Knuth–Morris–Pratt(KMP)算法是一种改进的字符串匹配算法,它的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。它的时间复杂度是O(m+n)。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。

什么时候会用到KMP算法?

字符串匹配问题,例如:实现strstr

KMP算法的主要思路

在之前遇到字符串匹配问题时,当模式串与主串匹配失败时,暴力求解法就是返回模式串的第一位和主串的下一位进行比较,而KMP利用了一个next数组减少了主串的回溯

举个例子:主串为“ababababca“,模式串为“abababca”

在暴力算法中当匹配到模式串中的‘c’时,需要返回模式串的第一位‘a’和主串的第二位‘b’,重新开始匹配

在KMP中,当遇到模式串的‘c’和主串中第四个‘a’不匹配时,会通过next数组返回上一个匹配成功的位置再接着与主串进行匹配,这个next数组中存入的就是字符串的前缀集合与后缀集合的交集中最长元素的长度。

  • 什么是字符串的前缀和后缀?
    如果字符串A和B,存在A=BS,其中S是任意的非空字符串,那就称B为A的前缀;同样可以定义后缀A=SB, 其中S是任意的非空字符串,那就称B为A的后缀。

举个例子:“hello”的前缀有:{‘h’,‘he’,‘hel’,‘hell’};后缀有:{‘ello’,‘llo’,‘lo’,‘o’}

构建next数组

void getNext (int *next, char *str02) { 
    int len02 = (int)strlen(str02);
    next[0] = 0; //设置next数组首元素为0
    int i, m;
    for (i = 1, m = 0; i < len02; i++) { //i为next数组下标,m为模式串下标
        next[i] = m; //上一个循环计算过的m
        while (m > 0 && str02[i] != str02[m]) { // 当m不在首位置并且模式串中字符失配时将m回溯到上一次匹配成功的地方进行判断
            m = next[m];
        }
        if (str02[i] == str02[m]) {//字符匹配时m加1
            m++;
        }
    }
    return;
}

在这里插入图片描述

strstr函数的实现

void getNext (int *next, char *str02) {
    int len02 = (int)strlen(str02);
    next[0] = 0;
    int i, m;
    for (i = 1, m = 0; i < len02; i++) {
        next[i] = m;
        while (m > 0 && str02[i] != str02[m]) {
            m = next[m];
        }
        if (str02[i] == str02[m]) {
            m++;
        }
    }
    return;
}
int kmp (char *str01, char *str02) {
    int next[100];
    getNext(next, str02);
    int i, j;
    int len01 = (int)strlen(str01);
    int len02 = (int)strlen(str02);
    for (i = 0, j = 0; i < len01; i++) { // 从0开始判断
        while (j > 0 && str02[j] != str01[i]) { 
            j = next[j];
        }
        if (str02[j] == str01[i]) { //字符匹配成功,i,j下标同时后移
            j++;
        }
        if(j == len02){ //模式串匹配完成
            return (i - j + 1); 
        }
    }
    return -1;
}

参考博客

kmp算法和kmp算法的优化

如何更好的理解和掌握KMP算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值