KMP算法(字符串匹配)
字数 1060 2025-11-13 04:11:45
KMP算法(字符串匹配)
题目描述
给定一个文本串text和一个模式串pattern,请你在text中找出pattern第一次出现的起始位置。如果pattern不是text的子串,则返回-1。
核心概念
- 文本串:待搜索的长字符串
- 模式串:要匹配的短字符串
- 前缀:包含首字母但不包含尾字母的连续子串
- 后缀:包含尾字母但不包含首字母的连续子串
暴力解法的问题
传统的暴力匹配需要回溯文本串指针,时间复杂度为O(m×n):
def brute_force(text, pattern):
m, n = len(text), len(pattern)
for i in range(m - n + 1):
j = 0
while j < n and text[i+j] == pattern[j]:
j += 1
if j == n:
return i
return -1
KMP核心思想
利用已匹配的信息,避免文本串指针的回溯。当出现不匹配时,模式串向右滑动到合适位置继续匹配。
关键步骤详解
步骤1:构建next数组
next数组存储模式串每个位置的最长相等前后缀长度:
- 初始化next[0] = 0,i = 1,j = 0
- 遍历模式串(i从1到n-1):
- 当pattern[i] != pattern[j]且j > 0时,j = next[j-1](回退)
- 当pattern[i] == pattern[j]时,j += 1
- next[i] = j
示例:pattern = "ABABC"
- i=1, j=0: 'B'≠'A' → next[1]=0
- i=2, j=0: 'A'='A' → j=1 → next[2]=1
- i=3, j=1: 'B'='B' → j=2 → next[3]=2
- i=4, j=2: 'C'≠'A' → j=next[1]=0 → 'C'≠'A' → next[4]=0
最终next = [0,0,1,2,0]
步骤2:利用next数组进行匹配
- 初始化i=0(文本串指针),j=0(模式串指针)
- 遍历文本串:
- 当text[i] == pattern[j]时,双指针同时右移
- 当不匹配且j>0时,j = next[j-1](模式串滑动)
- 当不匹配且j=0时,只移动文本串指针
- 当j == n时,返回i - n
完整代码实现
def kmp_search(text, pattern):
if not pattern:
return 0
# 构建next数组
def build_next(p):
next_arr = [0] * len(p)
j = 0
for i in range(1, len(p)):
while j > 0 and p[i] != p[j]:
j = next_arr[j-1]
if p[i] == p[j]:
j += 1
next_arr[i] = j
return next_arr
next_arr = build_next(pattern)
j = 0
# 开始搜索
for i in range(len(text)):
while j > 0 and text[i] != pattern[j]:
j = next_arr[j-1]
if text[i] == pattern[j]:
j += 1
if j == len(pattern):
return i - j + 1
return -1
复杂度分析
- 时间复杂度:O(m+n),其中m是文本串长度,n是模式串长度
- 空间复杂度:O(n),用于存储next数组
实际应用示例
text = "ABABABCABAB", pattern = "ABABC"
匹配过程:
- 前4个字符"ABAB"匹配成功
- 第5个字符' '≠'C',j回退到next[3]=2
- 从"ABA"开始继续匹配,最终找到完整匹配
KMP算法通过预处理模式串,实现了高效的字符串匹配,是许多文本编辑器和搜索引擎的基础算法。