LeetCode实现strStr()(Python)——KMP算法

题目

在这里插入图片描述

解题思路

经典的字符串匹配问题,那当然要用经典的KMP算法了,KMP算法实现起来还是有点复杂的,所以先暴力匹配开个胃:
在这里插入图片描述
时间复杂度看似是O(n),但实际上子字符串比较的时候,底层应该也是一个字符一个字符比较的,所以时间复杂度应该为O(m*n),一个有意思的地方在于needle=" “时,haystack切片[i :i+0]也是” ",所以不需要额外的判断。

执行结果为:
在这里插入图片描述

接下来实现KMP,首先就得先根据模板串needle去生成对应的next数组(又称部分匹配表),先上代码再讲解:
在这里插入图片描述

这里的部分匹配值(length)就是前缀和后缀中最长的共有子字符串,比如"ABA”的前缀为(“A”,“AB”),后缀为(“BA”,“A”),最长的共有子字符串为“A”,所以部分匹配值为1。而且,计算next数组的过程,也可以看作是一模一样的文本串和模板串在寻找公共前后缀字符串的过程(这一点后面也提到了)。另外,while分支和if分支的先后顺序也是有讲究的。下面以两个例子来讲解代码:

1.“ABCDABD”
第一次循环,当前计算“AB”的部分匹配值。i=1指向字符B,length=0指向字符A,不进入while分支,不进入if分支,最后length=0。

第二次循环,当前计算“ABC”的部分匹配值。i=2指向字符C,length=0指向字符A,不进入while分支,不进入if分支,最后length=0。

第三次循环,当前计算“ABCD”的部分匹配值。i=3指向字符D,length=0指向字符A,不进入while分支,不进入if分支,最后length=0。

第四次循环,当前计算“ABCDA”的部分匹配值。i=4指向最右边的字符A,length=0指向最左边的字符A,不进入while分支,进入if分支,length=1,最长共有子字符串为“A”。

第五次循环,当前计算“ABCDAB”的部分匹配值。i=5,指向字符B,length=1,指向字符B,不进入while分支,进入if分支,最后length=2,最长共有子字符串为“AA”。

第六次循环,当前计算“ABCDABD”的部分匹配值。i=6,指向字符D,length=2,指向字符C,进入while分支,此时length更新为length=next[1]=0,跳出while分支,然后不进入if分支,最后length=0。这里我着重讲一下,大概就能理解为什么要length=next[length-1],此时发现模板串前缀“ABC”和文本串后缀“ABD”不相同,如果按暴力匹配的想法,下一步应该是比较模板串前缀“AB”和文本串后缀“BD”,如果利用next[1]=0的信息,就相当于告诉你没有共有子字符串,于是直接往后移动,将模板串前缀的“A”滑动到文本串后缀的“D”后一位去(如果还有后一位的话)

2.“AACDAAA”

第一次循环,当前计算“AA”的部分匹配值。i=1指向字符A,length=0指向字符A,不进入while分支,进入if分支,length=1,最长共有子字符串为"A"。

第二次循环,当前计算“AAC”的部分匹配值。i=2指向字符C,length=1指向字符A,进入while分支,length更新为next[0]=0,此时指向字符A,跳出while分支,不进入if分支,最后length=0。

第三次循环,当前计算“AACD”的部分匹配值。i=3指向字符D,length=0指向字符A,不进入while分支,不进入if分支,最后length=0。

第四次循环,当前计算“AACDA”的部分匹配值。i=4指向最右边的字符A,length=0指向最左边的字符A,不进入while分支,进入if分支,length=1,最长共有子字符串为“A”。

第五次循环,当前计算“AACDAA”的部分匹配值。i=5指向字符A,length=1指向字符A,不进入while分支,进入if分支,最后length=2,最长共有子字符串为”AA“。

第六次循环,当前计算“AACDAAA”的部分匹配值。i=6,指向字符A,length=2,指向字符C,进入while分支,length更新为next[1]=1,指向字符A,needle[length]等于needle[i],跳出while分支,然后进入if分支,最后length=2,最长共有子字符串为”AA“。

我们运行一下程序,看是否与上述分析一致:
在这里插入图片描述

没问题,那下一步就是字符串进行匹配:
在这里插入图片描述

这一步代码和上面的很像,为什么会这么像呢?因为生成next数组这一步其实也可以看作是needle自己和自己进行前缀后缀字符串匹配,有没有get到!!!然后这段代码中,p_nee是模板串needle中的指针,p_hay是文本串中的指针,KMP的思想就是根据next数组中的信息,让p_hay坚决不后退。

再加上特殊情况的判断,在LeetCode上提交代码:
在这里插入图片描述
在这里插入图片描述

执行结果为:
在这里插入图片描述
意料之中~时间复杂度虽然降下来了,但代码毕竟从6行变成了21行,下次碰到字符串匹配的题再来练习BM算法和Sunday算法吧。

猜你喜欢

转载自blog.csdn.net/KeEN_Xwh/article/details/107806779
今日推荐