KMP算法

串的模式匹配算法

在kmp算法中,主串的指针不需要再回退,模式串字符不等于主串时,指针j根据next数组回退至next[j]。


求解next数组

原理(参考严蔚敏版数据结构):

通过递推的方式得到,如图为模式串

当已知红色区与蓝色区已经匹配时,,next[j]=i,求next[j+1]:

1)若p[i]==p[j]

    next[j+1]=next[j]+1;

2)当s[i]!=s[j]

可将next数组求值理解成在模式串中求字串的问题;

故next[j+1]=next[i]+1;

当然这种方式求出的next数组还可以更新为nextval数组,具体参考数据结构部分。

算法题直接背模板。

严蔚敏数据结构书中求next和nextval数组的判断条件及边界问题难以记忆,故我在这里参考了网上的其他代码,整体思路一致,只是next[i]数组变成当i+1与j不匹配时i应回退的位置(这与408要求的next数组不同),故在求next数组时应存在p[next[i]]==p[i]。

                 a    b    c    a    b
下标          1    2    3    4    5
next[ ]        0    0    0    1    2


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

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

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

#include<algorithm>
#include<iostream>

using namespace std;

const int N = 1e7+10;

char s[N], p[N];
int ne[N];
int n, m;
int main()
{
	cin >> n >> p + 1 >> m >> s + 1;
//ne[1]==0故跳过
	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&&p[j + 1] != s[i]) j = ne[j];
		if (p[j + 1] == s[i]) j++;
		if (j == n)
		{
			cout << i - n << " ";
			j = ne[j];
		}
	}
	return 0;
}

1)子串指针j都从0开始;

2)永远是子串j+1和主串i比较

3)不满足条件或已找到都要更新j

<think>好的,用户想了解KMP算法的原理及实现。首先,我需要回顾一下KMP的基本概念。KMP算法主要用于字符串匹配,解决传统暴力匹配中的重复遍历问题。传统方法在主串和子串部分匹配时,主串指针会回退,导致效率低下。而KMP通过预处理子串生成next数组,利用已知信息避免不必要的回溯,提高效率。 接下来,我需要解释KMP的核心原理。关键点在于next数组,它记录了子串每个位置的最长公共前后缀长度。当发生不匹配时,根据next数组的值调整子串的位置,主串指针无需回退。例如,在子串"ABABC"中,每个字符对应的next值需要明确说明如何计算。 然后是实现部分。需要详细说明如何构建next数组,通常包括初始化、处理前后缀相同和不同的情况。然后描述匹配过程,主串和子串指针的移动逻辑,特别是当不匹配时如何利用next数组跳转。可能还需要一个具体的例子来演示流程,比如主串"ABABABABC"和子串"ABABC"的匹配过程。 还要注意时间复杂度的分析,KMP的预处理是O(m),匹配是O(n),总的是O(n+m),比暴力法的O(n*m)更高效。同时,可能需要对比传统算法,突出KMP的优势,尤其是在有大量部分匹配的情况下。 用户提供的引用资料中提到next数组的构造类似于KMP算法本身,这一点需要强调,可能在代码实现中体现。另外,引用5提到前缀数组的计算方法,这应该包含在next数组的构建步骤中。 需要确保回答结构清晰,分点讲解原理、next数组构建、匹配步骤、代码实现和示例。最后生成相关问题,帮助用户进一步学习,如优化、应用场景、对比其他算法等。 在代码实现部分,要使用Python示例,并确保语法正确。同时,数学公式如计算最长公共前后缀时可能需要用LaTeX表示,如最长公共前后缀长度公式,使用$...$格式。 最后检查是否满足用户的所有要求,包括中文回答、LaTeX格式正确、引用标注自然等。确保回答正确可靠,参考了提供的引用资料,并正确标注来源。</think>### KMP算法原理及实现 #### 一、核心原理 KMP算法通过预处理子串生成**next数组**(即前缀函数),利用已匹配的信息避免主串指针回退。核心思想是:当子串与主串不匹配时,根据next数组的值调整子串的起始位置,而非暴力匹配中的逐字符回退。 1. **next数组定义** next数组存储子串每个位置$i$的最长公共前后缀长度(不包含自身)。例如子串$P=ABABC$的next数组为: $$next = [-1, 0, 0, 1, 2]$$ 其中,$next[4]=2$表示前缀$AB$与后缀$AB$匹配[^5]。 2. **匹配过程优化** - 主串指针$i$始终单向移动,子串指针$j$根据next数组跳转。 - 当$P[j] \neq T[i]$时,子串向右滑动$j - next[j]$位,即$j = next[j]$[^2][^4]。 #### 二、next数组构建步骤 以子串$P$为例(索引从0开始): 1. 初始化$next[0] = -1$,$j = -1$(哨兵节点)。 2. 遍历子串$P$,若$P[i] = P[j]$,则$next[i+1] = j + 1$。 3. 若$P[i] \neq P[j]$,则递归回退$j = next[j]$直至匹配或$j = -1$[^4]。 #### 三、算法实现(Python) ```python def build_next(pattern): next_arr = [-1] * len(pattern) j = -1 for i in range(1, len(pattern)): while j >= 0 and pattern[i] != pattern[j + 1]: j = next_arr[j] if pattern[i] == pattern[j + 1]: j += 1 next_arr[i] = j return next_arr def kmp_search(text, pattern): next_arr = build_next(pattern) j = -1 for i in range(len(text)): while j >= 0 and text[i] != pattern[j + 1]: j = next_arr[j] if text[i] == pattern[j + 1]: j += 1 if j == len(pattern) - 1: return i - j # 返回匹配起始位置 return -1 ``` #### 四、示例分析 假设主串$T=ABABABABC$,子串$P=ABABC$: 1. next数组为$[-1, 0, 0, 1, 2]$。 2. 当匹配到$T[4]$(字符A)与$P[4]$(字符C)不匹配时,子串跳转至$j=next[4]=2$,继续匹配[^2]。 #### 五、时间复杂度 - 预处理next数组:$O(m)$ - 匹配过程:$O(n)$ - 总时间复杂度:$O(n + m)$,优于暴力法的$O(n \times m)$[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值