字符串查找问题
给定文本串text和模式串pattern,从文本串text中找出模式串pattern第一次出现的位置。
暴力求解算法
Python代码
# 暴力求解
def brute_force_search(ss, s):
i = 0 # 当前匹配的原始字符串首位
j = 0 # 模式串的匹配位置
size = len(s)
nlast = len(ss) - size
while i <= nlast and j < size:
if ss[i + j] == s[j]: # 若匹配模式串位置后移
j += 1
else: # 若不匹配,则对比下一个位置,模式串回溯到首位
i += 1
j = 0
if j >= size:
return i
return -1
暴力求解的思路比较简单,这里就不在赘述。
KMP算法
当暴力求解不匹配的时候,每次都要再一次从模式串首位做匹配,如下图, x ! = y 时,每次右移1位,然后从头比较:
其实虚线中的移动都是多余的,直接移动到c所在的位置,比较c和x是否相等就可以了。所以关键是怎么在y求c所在的位置。观察模式串:
c 所在的位置就是 y 前面的字符串的最大相同前缀(ab)和后缀(ab)的数量 2 ,令 y 的next为2。
如果能把所有位置的next值都能够求出来,比较的时候,当字符不匹配时,模式串直接移动到next标识的位置,然后继续比较就可以了。这就是KMP算法。
求next就是求字符串的最大相等前缀和后缀:
如:j=7时,考察字符串“abcdeab”的最大相等k前缀和k后缀:
字符串“abcdeab”的最大相等k前缀和k后缀是"ab",值为2。
计算 next[ j ] 时,考察的字符串是模式串的前 j - 1 个字符,求其中最大相等的前缀和后缀的数量,与 s[ j ] 无关
next的递推关系
对于模式串的位置 j,有next[ j ] = k,即:p0p1…pk-2pk-1 = pj-kpj-k+1…pj-2pj-1
则,对于模式串的位置j+1,考察p[ j ]:
若p[ k ]==p[ j ](两个黄色部分相等)
next[ j+1 ]=next[ j ]+1
若p[ k ]≠p[ j ](灰色部分和黄色部分不相等)
记h=next[ k ],如果p[ h ]==p[ j ](紫色部分和黄色部分相等),则next[j+1]=h+1,
否则重复此过程。
Python代码
# 计算next数组
def get_next(s):
size = len(s)
next