C++数据结构7:KMP处理字符串

1、KMP概念

KMP(Knuth-Morris-Pratt)算法的核心在于 利用模式串自身的重复性,通过 预处理 next 数组 来优化匹配过程,避免主串回溯,从而提升匹配效率。其关键点可总结如下:

  • 主串不回溯:传统暴力匹配在失配时主串和模式串都要回溯,而 KMP 仅调整模式串的位置,主串指针 i 始终向前移动,避免不必要的重复匹配。
  • 利用 next 数组:next[j] 表示模式串 p[0..j] 的 最长相等前后缀长度,用于在失配时快速调整模式串的匹配位置。

2、实战项目

给定主串s,字串p,求解字串在主串的位置索引。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e6 + 10;  // 定义足够大的数组大小
char p[N], s[N];         // p是子串,s是主串(从索引0开始存储)
int ne[N];               // next数组(部分匹配表)

int main() {
    int n, m;            
    cin >> n >> p >> m >> s;
    ne[0] = -1;

    for (int i = 1, j = -1; i < n; i ++)  // 计算next数组(KMP预处理阶段)
    {
        while (j != -1 && p[i] != p[j + 1]) j = ne[j]; // 且当前字符不匹配时,回退j到ne[j]
        if (p[i] == p[j + 1])  j++; // 如果当前字符匹配,j向后移动
        ne[i] = j; // 记录当前位置的最长相等前后缀长度
    }

    // KMP匹配阶段(在主串s中查找模式串p)
    for (int i = 0, j = -1; i < m; i++) 
    {
        while (j != -1 && s[i] != p[j + 1])  j = ne[j]; //且当前字符不匹配时,回退j到ne[j]
        // 如果当前字符匹配,j向后移动
        if (s[i] == p[j + 1])   j++;
        if (j == n - 1) 
        {  
            cout << i - j << ' ';
            j = ne[j];             // 回退j,继续寻找
        }
    }
    return 0;
}

3、难点

难点就是求解next数组,也就是匹配表。

以abcab为例:

所有前缀组合:a, ab, abc, abca;   

所有后缀组合:b, ab, cab, bcab;

可以发现前缀规律:每一个前缀的开头一定是a字符;也就是在匹配表中,如果回溯1步,那么一定是回溯到a的位置;类似的,2步应该到ab位置,3步应该到abc位置。如果当前ne[j] = 2(0,1,2匹配),那么前面两个数也是可以回溯的,也就是前面j-1, j-2索引上的数也是匹配上了的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值