02KMP算法

Lingfeng2025-07-10

02KMP算法

1. 最长前缀后缀

Definition (最长前缀后缀 (Longest Prefix which is also Suffix, LPS))

对于字符串 ,第 个字符为 ,定义前 个 LPS 为

2. 课本实现

课本上的 KMP 算法数组和字符串索引都是从 1 开始,我们设模式串为 ,匹配串为

我们用 表示当第 个字符匹配失败时,应该跳转到的位置,即

其中

2.1 KMP 搜索

,需要找 的位置,因此只需找 。若正好有

则可以继续向前匹配。否则可能匹配的位置一定出现在前 之内,因此贪婪匹配 ,注意到有
因此自然带来递推实现。

下面给出代码实现,为了与实际 strlist 作区分,这里写作 StrLst,其中索引 0 表示长度。

def kmp_search(text: Str, pattern: Str, next: Lst[int]):
	n = text[0]
	m = pattern[0]
	j = 1

	for i in range(1, n + 1):
		while j > 0 and text[i] != pattern[j]:
			j = next[j]

		# 如果 text[i]==pattern[j], 此时 i, j 依次递增即可
		# 如果 text[i]!=pattern[j], 此时 j=0, j+=1 正好从 1 从头开始
		j += 1
		if j > m:
			return i - m + 1

	return -1

2.2 next 数组

下面需要找到 ,即 。对于 ,如果有

此时显然有 ,因此

如果不匹配,类似于 KMP 搜索,可能匹配的位置出现在前 之内,即 ,而注意到

因此依然是递推。

下面也给代码实现:

def get_next(pattern: Str) -> Lst[int]:
	m = pattern[0]
	next = Lst(m, 0)  # next[1] = 0
	k = 0

	for i in range(2, m + 1):
		while k > 0 and pattern[i - 1] != pattern[k]:
			k = next[k]

		k += 1
		next[i] = k

	return next

2.3 nextval 数组

按照前面的 KMP 搜索,如果 ,此时需要去找 。但是如果 ,也一定会有 ,此时需要额外的再去找 。因此不妨在建立 时就进行检测,直接令

就可以省去构建过程。

def get_nextval(pattern: Str) -> Lst[int]:
	m = pattern[0]
	nextval = Lst(m, 0)
	k = 0

	for i in range(2, m + 1):
		while length > 0 and pattern[i - 1] != pattern[k]:
			k = nextval[k]

		k += 1
		if pattern[i] == pattern[k]:
			nextval[i] = nextval[k]
		else:
			nextval[i] = k

	return nextval

3. 实际实现

实际实现中,字符串索引从 0 开始。此时 需要修改为

随之修改其余代码即可。

def kmp_search(text: str, pattern: str, next: list[int]):
	n = len(text)
	m = len(pattern)
	j = 0

	for i in range(n):
		while j >= 0 and text[i] != pattern[j]:
			j = next[j]

		j += 1
		if j == m:
			return i - m + 1

	return -1
def get_next(pattern) -> list[int]:
	m = len(pattern)
	next = [0] * m
	next[0] = k = -1

	for i in range(1, m):
		while k >= 0 and pattern[i - 1] != pattern[k]:
			k = next[k]

		k += 1
		next[i] = k

	return next
def get_nextval(pattern) -> list[int]:
	m = len(pattern)
	nextval = [0] * m
	nextval[0] = k = -1

	for i in range(1, m):
		k = nextval[i - 1]
		while k >= 0 and pattern[i - 1] != pattern[k]:
			k = nextval[k]

		k += 1
		if pattern[i] == pattern[k]:
			nextval[i] = nextval[k]
		else:
			nextval[i] = k

	return nextval
Last Updated 7/19/2025, 6:33:12 AM