字串串匹配——KMP算法

KMP

KMP是一种改进的模式匹配算法,它与朴素的模式匹配算法的区别在于:
每当匹配过程中出现比较字符不相等时,不需要回退主串的字符位置指针,而是利用已经得到的部分匹配结果将模式串向右滑动尽可能远的距离,再继续进行比较。

KMP匹配算法的思想

设模式串为p0 … pm-1,当模式串中的字符pj与主串中相应的字符Si不相等时,因其前j个字符p0 … pj-1已经获得了成功的匹配,若模式串的p0 … pk-1与pj-k … pj-1相同,这时可令Pk与Si进行比较,从而使i无须回退。

KMP算法中,依据模式串的next函数值实现子串的滑动。若令next[j]=k,则next[j]表示当模式串中的Pj与主串中相应字符不相等时,令模式串的Pnext[j]与主串的相应字符进行比较。

next函数的定义如下:

N e x t [ j ] = { − 1 ,    当 j = 0 时 m a x ( K ) ,    { K ∣ 0 < K < j 且 P 0... P k − 1 = P j − k . . . P j − 1 } 0 ,    其 它 情 况 Next[j] = \begin{cases} -1,\,\,当j=0时\\ max(K),\,\,\{K|0<K<j且P0...Pk-1=Pj-k...Pj-1\}\\ 0,\,\,其它情况\\ \end{cases} Next[j]=1,j=0max(K),{K0<K<jP0...Pk1=Pjk...Pj1}0,

示例代码

#include <iostream>
#include <string>

using namespace std;

// 求模式串p的next函数值,并存入数组next,要求next容量>=len(p)
void GetNext(const string &p, int next[])
{
    int i = 0;
    int j = -1;
    next[0] = -1;
    int len = p.length();

    while (i < len) {
        if (j == -1 || p[i] == p[j]) {
            ++i;
            ++j;
            next[i] = j;
        } else {
            j = next[j];
        }
    }
}

/*
 * 利用模式串p的next函数,求p在主串s中第一次出现的位置
 * 若匹配成功,返回模式串在主中的位置(下标),否则返回-1
 * */
int KMP(const string &s, const string &p, int next[])
{
    int i = 0;
    int j = -1;
    int sLen = s.length();
    int pLen = p.length();
    GetNext(p, next);

    while (i < sLen && j < pLen) {
        if (j == -1 || s[i] == p[j]) {
            ++i;
            ++j;
        } else {
            j = next[j];
        }
    }

    if (j >= pLen) {
        return i - pLen;
    }
    return -1;
}

int main() {
    string str = "abcccddddabcdabcd";
    string p = "abcd";
    int next[100];
    cout << KMP(str, p, next);

    return 0;
}

计算字符串中子串出现的次数与位置

/*
只需要在KMP中添加一个判断,当找到子串后,输出即可
*/
void KMP(const string &s, const string &p, int next[])
{
    int i = 0;
    int j = -1;
    int count = 0;
    int sLen = s.length();
    int pLen = p.length();
    GetNext(p, next);

    while (i < sLen && j < pLen) {
        if (j == -1 || s[i] == p[j]) {
            ++i;
            ++j;
        } else {
            j = next[j];
        }
        
        // 当满足条件时,输出次数与位置
        if (j == pLen) {
            j = 0;
            count++;
            cout << "count:" << count << " position:" << i-pLen+1 << endl; 
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KMP算法是一种字符串匹配算法,用于在一个文本S内查找一个模式P的出现位置。它的间复杂度为O(n+m),其n为文本的长度,m为模式的长度。 KMP算法的核心思想是利用已知信息来避免不必要的字符比较。具体来说,它维护一个next数组,其next[i]表示当第i个字符匹配失败,下一次匹配应该从模式的第next[i]个字符开始。 我们可以通过一个简单的例子来理解KMP算法的思想。假设文本为S="ababababca",模式为P="abababca",我们想要在S查找P的出现位置。 首先,我们可以将P的每个前缀和后缀进行比较,得到next数组: | i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | --- | - | - | - | - | - | - | - | - | | P | a | b | a | b | a | b | c | a | | next| 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 接下来,我们从S的第一个字符开始匹配P。当S的第七个字符和P的第七个字符匹配失败,我们可以利用next[6]=4,将P向右移动4个字符,使得P的第五个字符与S的第七个字符对齐。此,我们可以发现P的前五个字符和S的前五个字符已经匹配成功了。因此,我们可以继续从S的第六个字符开始匹配P。 当S的第十个字符和P的第八个字符匹配失败,我们可以利用next[7]=1,将P向右移动一个字符,使得P的第一个字符和S的第十个字符对齐。此,我们可以发现P的前一个字符和S的第十个字符已经匹配成功了。因此,我们可以继续从S的第十一个字符开始匹配P。 最终,我们可以发现P出现在S的第二个位置。 下面是KMP算法的C++代码实现:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值