
在字符串匹配问题中,KMP 算法以其高效性占据重要地位。它由 Knuth、Morris 和 Pratt 三位科学家共同提出,通过巧妙的预处理机制,将传统匹配的 O (n*m) 时间复杂度优化至 O (n+m)成都股票配资,尤其适用于长文本与模式串的匹配场景。本文将从算法原理、核心思想到代码实现,全面剖析 KMP 算法的工作机制。
一、问题引入:传统匹配的痛点
字符串匹配的核心任务是:给定文本串text(长度为 n)和模式串pattern(长度为 m),判断模式串是否为文本串的子串,若存在则返回首次出现的位置。
传统暴力匹配(BF 算法)的思路简单直接:
从文本串第 i 位、模式串第 j 位开始比较 若字符匹配(text[i] == pattern[j]),则 i、j 同时后移 若不匹配,i 回溯至i-j+1,j 重置为 0这种方式在最坏情况下效率极低。例如当文本串为"AAAAA..."且模式串为"AAAB"时,每次匹配失败都需回溯 i,产生大量无效比较。
二、KMP 算法的核心:避免无效回溯
展开剩余91%KMP 算法的突破在于让文本串指针 i 永不回溯,仅通过调整模式串指针 j 来实现高效匹配。其核心是利用模式串自身的前缀和后缀信息,计算出部分匹配表(Partial Match Table,简称 PMT),也称为失效函数(failure function)。
1. 前缀与后缀的定义
前缀:模式串中除最后一个字符外,所有以第一个字符开头的连续子串 后缀:模式串中除第一个字符外,所有以最后一个字符结尾的连续子串 最长公共前后缀(LCP):前缀和后缀中长度最长的相同子串例如模式串"ABABC":
子串"AB"的前缀为["A"],后缀为["B"],LCP 长度为 0 子串"ABA"的前缀为["A", "AB"],后缀为["A", "BA"],LCP 长度为 1("A")2. 部分匹配表(PMT)的构建
PMT 是一个与模式串等长的数组,其中pmt[j]表示模式串前j+1个字符组成的子串的最长公共前后缀长度。
以模式串"ABABC"为例,其 PMT 如下:
索引 j子串最长公共前后缀pmt[j]0"A"无01"AB"无02"ABA""A"(长度 1)13"ABAB""AB"(长度 2)24"ABABC"无0
PMT 计算代码实现:
python
运行
def compute_pmt(pattern):
m = len(pattern)
pmt = [0] * m # 初始化PMT数组
length = 0 # 记录当前最长公共前后缀长度
pygame,draw,rect(screen, (255,0,0), (x,y,width,height), border_radius=5)
pygame,draw,;foot.ttzb24h.com@163.com;circle(screen, (0,255,0), (center_x,center_y), radius)
pygame,draw,line(screen, (255,255,0), start_pos, end_pos, width=3)
player_img = pygame,image,load("spaceship,png"),convert_alpha()
screen,;fifa.ttzb24h.com@163.com;blit(player_img, (x,y)) # 支持透明通道
angle = (angle + 5) % 360
rotated_img = pygame,transform,rotate(original_img, angle)
new_rect = rotated_img,get_rect(center=original_rect,center)
screen,;nba.ttzb24h.com@163.com;blit(rotated_img, new_rect,topleft)
i = 1
while i < m:
if pattern[i] == pattern[length]:
length += 1
pmt[i] = length
i += 1
else:
if length != 0:
# 回溯到上一个可能的最长前缀
length = pmt[length - 1]pygame,draw,rect(screen, (255,0,0), (x,y,width,height), border_radius=5)
pygame,draw,;bund.ttzb24h.com@163.com;circle(screen, (0,255,0), (center_x,center_y), radius)
pygame,draw,line(screen, (255,255,0), start_pos, end_pos, width=3)
player_img = pygame,image,load("spaceship,png"),convert_alpha()
screen,;lalig.ttzb24h.com@163.com;blit(player_img, (x,y)) # 支持透明通道
angle = (angle + 5) % 360
rotated_img = pygame,transform,rotate(original_img, angle)
new_rect = rotated_img,get_rect(center=original_rect,center)
screen,;seria.ttzb24h.com@163.com;blit(rotated_img, new_rect,topleft)
else:
pmt[i] = 0
i += 1
return pmt
代码解析:
初始化length=0,从模式串第 2 个字符(i=1)开始计算 当字符匹配时,延长公共前后缀长度并记录到 PMT 当字符不匹配时,通过length = pmt[length-1]回溯,避免从头比较三、KMP 匹配过程
有了 PMT 数组后,匹配过程如下:
初始化文本串指针i=0,模式串指针j=0 若text[i] == pattern[j],则 i、j 同时后移 若不匹配: 若 j != 0,令j = pmt[j-1](利用 PMT 调整模式串位置) 若 j == 0,令 i += 1(文本串后移一位) 当 j == m 时,匹配成功,返回i - j(首次出现位置)匹配算法代码实现:
python
运行
def kmp_search(text, pattern, pmt):
n = len(text)
m = len(pattern)
i = 0 # 文本串指针
j = 0 # 模式串指针
while i < n:
if text[i] == pattern[j]:
i += 1
j += 1
if j == m:
return i - j # 返回匹配起始位置
else:
if j != 0:
j = pmt[j - 1] # 关键:利用PMT回溯j
else:
i += 1
return -1 # 未找到匹配
pygame,draw,rect(screen, (255,0,0), (x,y,width,height), border_radius=5)
pygame,draw,;ig1.ttzb24h.com@163.com;circle(screen, (0,255,0), (center_x,center_y), radius)
pygame,draw,line(screen, (255,255,0), start_pos, end_pos, width=3)
player_img = pygame,image,load("spaceship,png"),convert_alpha()
screen,;prem.ttzb24h.com@163.com;blit(player_img, (x,y)) # 支持透明通道
angle = (angle + 5) % 360
rotated_img = pygame,transform,rotate(original_img, angle)
new_rect = rotated_img,get_rect(center=original_rect,center)
screen,;ucl.ttzb24h.com@163.com;blit(rotated_img, new_rect,topleft)
示例演示:
文本串:"ABABABC" 模式串:"ABABC" PMT 数组:[0,0,1,2,0]匹配过程中,当 i=4、j=4 时(text[4]="A" vs pattern[4]="C")不匹配,此时 j 回溯至pmt[3]=2,直接从pattern[2]开始继续比较,避免了 i 的回溯,大幅减少无效操作。
四、优化:next 数组的使用
实际实现中,常对 PMT 进行偏移处理得到next 数组,令next[j] = pmt[j-1](j>0 时),这样在不匹配时可直接使用j = next[j],简化代码逻辑。
python
运行
def compute_next(pattern):
m = len(pattern)
next_arr = [0] * m
length = 0
i = 1
while i < m:
if pattern[i] == pattern[length]:
length += 1
next_arr[i] = length
i += 1
else:
if length != 0:
length = next_arr[length - 1]
else:
next_arr[i] = 0
i += 1
# 对next数组进行偏移处理
for i in ;;range(m-1, 0, -1):
next_arr[i] = next_arr[i-1]
next_arr[0] = -1
return next_arr
使用 next 数组的匹配代码与 PMT 版本类似,仅需将j = pmt[j-1]改为j = next_arr[j]。
五、应用场景与性能分析
KMP 算法在以下场景中表现优异:
文本编辑器的查找功能 基因序列匹配(生物信息学) 网络入侵检测(特征串匹配)性能方面,预处理阶段(计算 PMT/next 数组)时间复杂度为 O (m),匹配阶段为 O (n),整体达到线性效率。相比 BF 算法,在模式串与文本串存在大量重复前缀时,优势尤为明显。
KMP 算法通过预处理模式串构建部分匹配表,成功避免了文本串指针的回溯,实现了字符串匹配的线性时间复杂度。其核心思想是利用已有的匹配信息减少无效比较,这种 "以空间换时间" 的策略,为处理大规模字符串匹配问题提供了高效解决方案。
掌握 KMP 算法不仅能提升代码效率成都股票配资,更能培养对问题本质的洞察 —— 通过分析数据内在规律,找到优化突破口。在实际开发中,可根据具体场景选择 PMT 或 next 数组实现,兼顾可读性与性能。
发布于:湖南省豪瑞优配提示:文章来自网络,不代表本站观点。