字符串比较——KMP

字符串比较——KMP

本文主要内容:

  1. 基础复习
  2. KMP求字符串最小循环节

1 基础复习

  • 主要功能
  1. 字符串匹配
  2. 求字符串最小循环节
  • 时间复杂度
    o(n)
  • 基本思路:
    1.不用kmp算法只要文本串S(长度为n)与搜索串P(长度为m)对应的某一个字符不同,P就往后滑动1位再从头开始比较,用了kmp算法P滑动k位(k>=1 && k < m)从原位置进行比较
  1. 用一个next[]数组记录P的所有位置的最长匹配前缀(前缀等于后缀的最长前缀)长度,当比较S和P时只要有一个字符不同,P进行滑动(j=next[j]),使已经P和S已经匹配的那段中P的最长匹配前缀与S的后缀对齐,继续进行比较
  2. 构建next[]与比较S和P是否相等的过程相似,区别在于构建next[]比较的是P的后缀和P的前缀是否相等
  • 注意事项:
  1. j指向的是已经匹配的p的末尾,待匹配的是P[j+1],因为next[j]维护的是以处的最长匹配前缀长度。

模板题:Acwing831.KMP字符串

#include<iostream>

using namespace std;

const int N = 1e6 + 5;

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

int main()
{
    cin >> n >> p + 1 >> m >> s + 1;
    for(int i = 2, j = 0; i <= n; i++)
    {
        while(j && p[j + 1] != p[i])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)
        {
            cout << i - n << " ";
            j = ne[j];
        }
    }
    return 0;
}

2 KMP求字符串最小循环节

例题:Acwing141. 周期

  • 思路:
  1. 任意一段字符的最小循环节长度等于i-next[i]
  2. 构建字符串的next[],遍历一遍该字符串即可求得具有循环节的前缀串的位置和循环节数量
#include<iostream>

using namespace std;

const int N = 1e6 + 5;

int ne[N];
char str[N];
int n;

void get_next()
{
    for(int i = 2, j = 0; i <= n; i++)
    {
        while(j && str[j + 1] != str[i])j = ne[j];
        if(str[j + 1] == str[i])j++;
        ne[i] = j;
    }
}
int main()
{
    int T = 0;
    while(scanf("%d", &n), n)
    {
        scanf("%s", str + 1);
        get_next();
        printf("Test case #%d\n", ++T);
        for(int i = 1; i <= n; i++)
        {
            int t = i - ne[i];  //t为前缀最小循环节
            if(t != i && i % t == 0)
                printf("%d %d\n", i, i / t);
        }
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值