想了解更多请查看:https://blog.csdn.net/qq_55364042/article/details/130098343?spm=1001.2014.3001.5501
KMP的设计之初是为了实现在一个大字符串A中找出一个某个小字符串a
例(1):在'deabcfgabcabcd' 中找出‘abcabc’
如果纯暴力的话 时间复杂度为O(n^2)
下标跳转数组
现在让我们假设有一种数组(arr),他的每一位下标代表了截止到当前为止’前后缀相同的‘‘最长的’长度,例(2):abcabc 的arr为【0,0,0,0,1,2,3】,注意我们的下标从1开始数
例(3):aaaa的arr为【0,0,1,2,3】
如果说我们的a有这样一个数组,那么就会很方便
思维
设:i为A的下标指针,j为a的下标指针,j最少会比i小1且从外加的一个空字符开始
当A【i】==a【j】: i+=1 ,j+=1
当A【i】!=a【j】 :i=i , j=arr跳转至第一个等于A【i】的位置,证明如下
首先A是比a长的,所以在A中找a的时候,A中要有一个开头下标 设为q
设A【q~(i-1)】等于a【0~j】,那么A【q~(i-1)】.前缀/后缀 == a【0~j】.前缀/后缀
又 前后缀是相等的,所以A【q~(i-1)】.后缀 == a【0~j】.前缀
所以j可以通过arr跳转至a的前缀结尾下标
那么当我们在A中找a的时候,每次匹配失败时,a的j就不是暴力的每次跳到开头 而是跳到前缀结尾处,那么就节省了大量的时间,可以说是O(n)的
代码实现
A=' '+input()#大串
a=' '+input()#小串
arr=[0 for i in range(len(a))]#下标跳转数组
j=0
for i in range(2,len(a)):#跑出下标跳转数组
while j and a[j+1]!=a[i]:#跳转至可匹配的前缀结尾处
j=arr[j]
if a[j+1]==a[i]:
j+=1
arr[i]=j
def Find(A,a,arr):
j=0
for i in range(1,len(A)):
while j and a[j+1]!=A[i]:
j=arr[j]
if a[j+1]==A[i]:
j+=1
if j==len(a)-1:
return True
return False
if len(A)<len(a):
print('输入有误')
elif Find(A,a,arr):
print('A中有a')
else:
print('A中无a')