【Algorithm】KMP

KMP -- 字符串的匹配问题

给定一个模式串 S,以及一个模板串 P,所有字符串中只包含大小写英文字母以及阿拉伯数字。模板串 P 在模式串 S 中多次作为子串出现。求出模板串 PP 在模式串 SS 中所有出现的位置的起始下标。

暴力:只要枚举文本串的起始位置 i,然后从该位开始逐位与模式串进行匹配,如果匹配过程中每一位都相同,则匹配成功;否则,只要出现某位不同,就让文本串的起始位置变为 i + 1,并且从头开始模式串的匹配。这种做法的时间复杂度为 O(n * m)。

for (int i = 1; i <= n; i++) {
    bool flag = true;
    for (int j = 1; j <= m;j++) {
        if(s[i+j-1] != p[j]) {
            flag = false;
            break;
        }        
    }
}

假定有一个字符串 s(下标从 1 开始),那么它以 i 号位作为结尾的子串就是 s[1...i]。对该子串来说,长度为 k 的前缀和后缀分别是 s[1...k] 和 s[i-k+1...i]。现在定义一个 next 数组(说实话,这名字真奇怪QwQ),其中 next[i] 表示使子串 s[1...i] 的前缀 s[1...k] 等于后缀 s[i-k+1...i] 的最大的 k (注意:前缀跟后缀可以部分重叠,但不能是 s[0...i] 本身);如果找不到相等的前后缀,那么就令 next[i] = 0。显然,next[i] 就是所求最长相等前后缀中前缀最后一位的下标

#include <iostream>

using namespace std;

const int N = 100010, M = 1000010;

int n, m;
int ne[N];
char s[M], p[N];

int main()
{
    cin >> n >> p + 1 >> m >> s + 1;

    for (int i = 2, j = 0; i <= n; i ++ )
    {
        while (j && p[i] != p[j + 1]) j = ne[j];
        if (p[i] == p[j + 1]) j ++ ;
        ne[i] = j;
    }

    for (int i = 1, j = 0; i <= m; i ++ )
    {
        while (j && s[i] != p[j + 1]) j = ne[j];
        if (s[i] == p[j + 1]) j ++ ;
        if (j == n)
        {
            printf("%d ", i - n);
            j = ne[j];
        }
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值