kmp算法思想
两个字符串匹配,kmp算法时间复杂度O(m+n)。总体思想就是对于匹配子串,利用先验知识尽可能的不重复匹配。
next数组的定义
对于子串,计算出当前字符之前字符串中相同字符的个数,这样在子串和字符串当前字符匹配不成功时,就可以直接跳转到之前字符串相同的位置的下一个,减少了匹配的次数。
例如:abab,next数组为[0,0,0,1],表示当前字符匹配不成功时,前面字符串包含的相同子串的长度,最后一个b,前面的子串为aba,包含相同子串为a,个数为2,需要跳转到下标为1的位置,所以next值为1;
进一步优化next,解决aaaab这种特殊情况,原始next数组为:[0, 0, 1, 2, 3],可以看到aaaa为连续相同字符,即使按照next数组进行了跳转,跳转后的字符和当前字符是相同的,这是没有意义的,为了解决这一 问题,就需要对next数组进行优化,得到[0, 0, 0, 0, 3],当跳转后的字符与当前字符相同时,就继续进行跳转,直到跳转后的字符与当前字符不同,或者到字符串最开始0位置。
构建好next数组后,就可以将字符串与子串进行匹配操作。字符串从头到尾遍历,如果遍历的当前字符与子串相同,就继续,如果不同,则子串查询next数组,跳转到next中的位置,继续遍历比较。
def data_next(str_data):
tmp_data = str_data
i = 1
j = 0
data_next = [0]
# 求字符串中前缀和后缀相同的个数
while i < len(str_data):
if str_data[i] == tmp_data[j]:
i += 1
j += 1
data_next.append(j)
else:
j = 0
if str_data[i] == tmp_data[j]:
data_next.append(1)
else:
data_next.append(0)
i += 1
# next数组整体右移一位,当前数组表示字符不匹配是跳转的字符串下标
data_next = [0] + data_next[:-1]
print("原始next数组:"+str(data_next))
# next数组优化,当next数组中的跳转字符与当前字符相同时,需要继续跳转,知道跳转后字符与当前字符不同为止或者调到最开始
for index in range(len(data_next)):
index_str = str_data[index]
next_new = data_next[index]
while str_data[next_new] == index_str and next_new != 0:
next_new = data_next[next_new]
data_next[index] = next_new
print("优化后next数组:"+str(data_next))
return data_next
def data_match(data_1, data_2, data_next):
j = 0
for i in data_1:
if j == len(data_2)-1:
return True
elif i == data_2[j]:
j += 1
else:
j = data_next[j]
return False
if __name__ == '__main__':
ss = 'ababaaababaa'
ll = 'aaaab'
next = data_next(ll)
print(data_match(ss, ll, next))