首页 > 编程语言 >字符串匹配——KMP算法

字符串匹配——KMP算法

时间:2024-09-20 19:24:10浏览次数:3  
标签:字符 下标 int ne 后缀 算法 KMP 字符串

目录

题目描述

输入格式

输出格式

数据范围

输入样例

输出样例

思路解析 

纯享版代码

题目描述

给定一个字符串 S,以及一个模式串 P,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模式串 P 在字符串 S 中多次作为子串出现。

求出模式串 P 在字符串 S 中所有出现的位置的起始下标。

输入格式

第一行输入整数 N,表示字符串 P 的长度。

第二行输入字符串 P。

第三行输入整数 M,表示字符串 S 的长度。

第四行输入字符串 S。

输出格式

共一行,输出所有出现位置的起始下标(下标从 0 开始计数),整数之间用空格隔开。

数据范围

1≤N≤1e5
1≤M≤1e6

输入样例

3
aba
5
ababa

输出样例

0 2

思路解析 

下面给出KMP的算法思路:

图解一
图解二

图解三

       上面的图应该能让您对KMP有个初步了解,接下来我将提供KMP字符串匹配的代码,并添加较为详细的注释来帮助您理解,并且我会用相同的颜色将代码与注释对应起来,紧接着我将给出最终纯享版代码,为了方便大家对题目有一个很好的调试,

题目连接://http://47.110.135.197/problem.php?id=6771
#include<iostream>
#include<string>
using namespace std;
const int N=100000;
int ne[N];
int main()
{
    int n,m;
    string p,s;
    cin>>n>>p>>m>>s; 

下面红颜色的注释对应图解二
    //求解next数组,next数组是当前字符最长的相等前缀和后缀的长度
    //例如“aadaaf”的每个字符的前后缀长度分别为“0,1,0,1,2,0”
    //这里解释第二个和第三个即可理解含义:第二个的字符是a,则前两个字符里面,相等:前缀为a,后缀也为a,所以为1
    //第五个字符,前五个字符里面,相等:前缀为aa,后缀也为aa,所以为2
    //输入的s字符串,第一个字符下标从0开始

//下面的过程对应图解三
    ne[0]=0;//所以第一个字符的最长前缀和后缀一定为0
    int j=0;//j是前缀末尾
    for(int i=1;i<=n;i++)//i是后缀末尾,由于要比较前后缀,所以将j初始化为0,将i初始化为1
    {
        //当前后缀不相同时,就让j回到找前面所有字符的相同前后缀,这样即可继续匹配,即next数组的j-1下标
        while(j>0&&p[i]!=p[j])//当p[i]==p[j]时执行下面的操作,当j到0的时候就不用回退了
        {
            j=ne[j-1];//回退到前面所有字符前后缀相同的下标
        }
        //当前后缀相同时
        if(p[i]==p[j]) j++;//前缀末尾就加1,说明相同前后缀的长度多了1
        ne[i]=j;//前i个字符里面,前后缀相同的长度就是j
    }

//下面的过程对应图解一
    for(int i=0,j=0;i<m;i++)//此时i和j分别代表s和p的遍历下标
    {
        while(j>0&&s[i]!=p[j]) j=ne[j-1];//当遍历到两字符串不相等时,j进行回退到前后缀相同的位置下标
        if(s[i]==p[j]) j++;//如果相等,继续匹配下一个字符
        if(j==n)//当j遍历到p的末尾时,说明模式串完全匹配
        //这里为什么不是n-1呢,因为n-1的时候也要验证一下,j++就变成n了
        {
            cout<<i-n+1<<" ";//用当前的i-模式串的长度+1就是刚出现时的下标
            j=ne[j-1];//然后j回退,继续匹配下一个出现的位置
        }
    }
    return 0;

纯享版代码

#include<iostream>
#include<string>
using namespace std;
const int N=100000;
int ne[N];
int main()
{
	int n,m;
	string p,s;
	cin>>n>>p>>m>>s;
	ne[0]=0;
	int j=0;
	for(int i=1;i<=n;i++)
	{
		while(j>0&&p[i]!=p[j])
		{
			j=ne[j-1];
		}
		if(p[i]==p[j]) j++;
		ne[i]=j;
	}
	for(int i=0,j=0;i<m;i++)
	{
		while(j>0&&s[i]!=p[j]) j=ne[j-1];
		if(s[i]==p[j]) j++;
		if(j==n)
		{
			cout<<i-n+1<<" ";
			j=ne[j-1];
		}
	}
	return 0;
}

标签:字符,下标,int,ne,后缀,算法,KMP,字符串
From: https://blog.csdn.net/r2931887650/article/details/142340199

相关文章