左成云算法进阶班(1)-KMP (python)

问题:给定一下两个字符串str(n位)与ptr(m位),求ptr在srt中出现的次数或者其出现的位置
str = “ababacababadababadadda”;
ptr = “ababad”;

暴力破解的时间复杂度是O(n*m),可以用KMP算法去简化。下面简述一下KMP算法的思路。
1.next数组是怎么产生的?
next第一位是-1,第二位是0,长度和子串长度一致。假设i-1前面已经产生了最大的子串的长度cn,那么首先比较cn后面的字符(其实就是str2[cn])是否等于第i-1位置的字符(因为从0计数,所以就是cn位置),如果相等,那么i位置的最长子串就是cn+1。如果不等,就找cn前一个字符的最长子串,再分成两坨继续寻找,最后没有那就这个位置的最长前缀是0,继续往后找。

2.KMP思路:
两个指针,,如果i和j的字符一致,都++,如果不一致,此时判断next[j]是不是-1,因为0位置是-1,str1和str2中第一个字符都不配,那么str1只能往后移了。如果没有前退到-1,那么就退到next[j]的位置上,因为从next[j]开始,和next[j]前面是重复的,可以跳过中间的不用比较。
最后判断j是不是走完了str2,如果是,就说明找到了,不是那就没找到。

def get_next(str2):
	#构造next数组
	if len(str2) == 1:
		return -1
	next_a = [0] * len(str2)
	next_a[0], next_a[1] = -1, 0
	i = 2
	cn = 0 #跳到的位置
	while i < len(str2):
		#如果跳到的位置和前一个字符相同,那么最长前缀就是cn+1
		#xxx(4个)  ...  xxx(4个)  x(第i-1号位置,最长前缀是4) x(第i号位置)
		#str2[cn]是第五个数,从0开始计数
		if str2[i-1] == str2[cn]:
			cn += 1
			next_a[i] = cn
			i += 1
		#如果不等,那么就往前跳,在分两坨。
		elif cn > 0:
			cn = next_a[cn]
		else:
			next_a[i] = 0
			i += 1
	return next_a

def KMP(str1, str2):
	next_a = get_next(str2)
	i, j = 0, 0
	while i < len(str1) and j < len(str2):
		if str2[j] == str1[i]:
			i += 1
			j += 1
		#0位置是-1,str2中第一个都不配,那么str1只能往后移了。
		elif next_a[j] == -1:
			i += 1
		else:
			j = next_a[j]
	if j == len(str2):
		return i - j
	else:
		return -1
string1 = 'aabcy'
substring = 'abcy'
res = KMP(string1, substring)
print(res)

你可能感兴趣的:(leetcode)