学习来源
问题描述
字符串匹配问题:给定主串S = 'abcabd'
和模式串A = 'abd'
,求解S
中第一次出现A
的位置,若S
中不存在A
则返回-1
。tips:
需要注意题目中针对空模式串的处理方式。Leetcode28题要求返回0
。
朴素解法
将模式串与主串的所有字串逐一比较,首先通过模式串长度直接判断是否小于主串,满足条件则进行匹配比对。在匹配过程中,每次从主串选择与模式串等长的字串进行匹配,若无法匹配则继续遍历主串,选取下一个字串。
朴素解法的时间复杂度为O((len(main)-len(pattern)*len(pattern))
。
该方法优点在于直观、易操作、代码简短,但是容易超时 ,一般题目都会要求处理较大数据。
lens_main = len(main)
lens_pattern = len(pattern)
if lens_pattern == 0:
return 0
for i in range(lens_main - lens_pattern + 1):
if main[i: i + lens_pattern] == pattern:
return i
return -1
双指针法
point_m
指向主串,point_p
指向模式串,若不匹配,则point_p
置0
,假设本次匹配起点索引为s
,则point_m
重置为s+1
(s
是本次索引的起点,本轮匹配失败则主串索引加一,因此为s+1
)。该方法的时间复杂度同样为O((len(main)-len(pattern)*len(pattern))
。
lens_main = len(main)
lens_pattern = len(pattern)
if lens_pattern == 0:
return 0
p_main = 0
while p_main < lens_main - lens_pattern + 1:
# 找到开始位置
while p_main < lens_main - lens_pattern + 1 and main[p_main] != pattern[0]:
p_main += 1
# 初始化模式串指针
p_pattern = 0
start = p_main
while p_pattern < lens_pattern and p_main < lens_main and main[p_main] == pattern[p_pattern]:
p_main += 1
p_pattern += 1
# 若匹配完毕则返回主串中的索引
if p_pattern == lens_pattern:
return p_main - lens_pattern
# 若没有完全匹配,则更新主串索引
p_main = start + 1
return -1
KMP算法
在双指针方法中,每次更新时都会初始化模式串索引为0
,匹配失败的位置信息直接被抛弃。KMP
算法正是针对主串与模式串匹配失败的信息来更新模式串索引,这些信息通常使用next
数组进行存储。
KMP
算法的核心就是如何构建next
数组,进而避免每次匹配失败后,都需要从模式串的开头进行重新匹配。其中,next[i]
表示若pattern[i]
无法匹配,则模式串索引应当跳转至next[i]
处。学习后发现,next[i]
就是模式串的子串:pattern[:i]
中,最长公共前缀后缀的长度。
def make_next(pattern):
lens = len(pattern)
next_list = [0 for _ in range(lens)]
next_list[0] = -1
p_main = 0
p_pattern = -1
while p_main < lens - 1:
if p_pattern == -1 or pattern[p_main] == pattern[p_pattern]:
p_main += 1
p_pattern += 1
next_list[p_main] = p_pattern
else:
p_pattern = next_list[p_pattern]
return next_list
def kmp(main, pattern):
lens_main = len(main)
lens_pattern = len(pattern)
if lens_pattern == 0:
return 0
p_main = p_pattern = 0
next_list = make_next(pattern)
while p_main < lens_main and p_pattern < lens_pattern:
if main[p_main] == pattern[p_pattern] or p_pattern < 0:
p_main += 1
p_pattern += 1
else:
p_pattern = next_list[p_pattern]
if p_pattern != lens_pattern:
return -1
else:
return p_main - lens_pattern + 1
匹配算法还有很多,暂时记录,日后补充学习。
Horspool、Sunday算法、BM