前言
KMP算法:用于寻找s串中是否包含a串
算法思路
思路:暴力解法中使用
(
i
,
j
)
(i,j)
(i,j)遍历,i指向s串,j指向a串,每次匹配一遍a串,
i
i
i指往前了a.length()步后又要回退到(
i
i
i_初始+1)处。而KMP算法利用每次匹配a串过程中的已知信息,使
i
i
i指针不用回退。如下图所示,如果"ABC"部分A等于C,则可以直接跳过A部分的比较,而
i
i
i也不用回退,继续比较子串的剩余部分即可。
实现:
- a串拥有一个int[] next=getNext()数组。
- i i i遍历s串。
- j j j指向a串,且 j j j是跳变的。//所以只有一层for循环
- 如果当前 s [ i ] = a [ j ] s[i]=a[j] s[i]=a[j]则 i i i和 j j j均向前移动。
- 如果不相等,则将 j j j指针跳到 n e x t [ j − 1 ] next[j-1] next[j−1]处。注意,此处是 w h i l e while while,只要不相等就一直往前跳。如果退出情况是相等,则 j j j往后移一格(因为下一轮循环会 i i i++);如果退出之后仍然不相等,则表明 j j j移动到a串的头部了,此时不做处理,开始下一轮的 i i i++循环。
解释
如果不相等,则将
j
j
j指针跳到
n
e
x
t
[
j
−
1
]
next[j-1]
next[j−1]处:如果
s
[
i
]
!
=
a
[
j
]
s[i]!=a[j]
s[i]!=a[j],则看a串[0,j-1]部分的最长相同前后缀,可以跳过开头的相同部分。
getNext
介绍:返回子串a的next数组。next[
i
i
i]表示[0,
i
i
i]区间的最长相同前后缀的长度。
思路:讲解
- 如Fig.1所示,已知 R R R部分元素的next值,R部分最长公共前后缀的长度为 R L R_L RL=next[6]=3。所以求next[7],可以先比较next[ R L R_L RL]是否与a[7]相等,如果相等,那么next[ R L R_L RL]=next[6]+1。图中不相等,故要继续求解。
- 如Fig.2所示继续观察串R部分,如果R部分①所画双横线部分相等,则看a[2]是否和a[7]相等,如果相等则next[7]=3。如果①部分不相等则看②部分,如果②所画双横线部分相等,则看a[1]是否和a[7]相等,如果相等则next[7]=2。所以总结起来就是:(下述伪代码没有考虑很多细节,只为理解方便)
//R->缩为自己的最长公共前缀,即
R_L=next[R_L]=3
if(a[R_L]==s[7]) next[7]=R_L+1;
else{
R_L = next[R_L];//这里还要考虑是否已经为0,如果已经为0,则代表没有和s[7]相等的部分,next[7]直接为0
}
实现:
public void getNext(int[] next,String s){
next[0]=0;
int i=1;
int prelen=0;//当前共同前后缀长度,即串"(xxx)i"的(xxx)部分的共同前后缀长度为prelen
//此时,需要看s[prelen]和i是否相等
while(i<s.length()){
if(s.charAt(i)==s.charAt(prelen)){
next[i] = ++prelen;//是++i而不是i++
i = i+1;
}
else{
if(prelen==0){
next[i]=0;
i = i+1;
}else{
prelen = next[prelen-1];
}
}
}
}
注释:还有一种双指针实现,没有上面容易理解讲解
KMP用文字解释起来好无力,看动画解释比较好。确实绕,看代码比看文字强,好难解释/(ㄒoㄒ)/~~
具体题目
一、28题(实现 strStr())
题目描述:
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1: 输入: haystack = “hello”, needle = “ll” 输出: 2
示例 2: 输入: haystack = “aaaaa”, needle = “bba” 输出: -1
题解
一些备注
在这里插入代码片
算法思路:
易错点:
备注:
- Arrays.toString(next);//输出数组,避免遍历输出
- 最好记住一组很好的案例,这样一边写程序一边核对案例就不会出错。
①对于getNext: abacabab
②对于主程序:abacabab 和 abab
二、459题(重复的子字符串)
题目描述:
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
输入: “abab”
输出: True
解释: 可由子字符串 “ab” 重复两次构成。
在这里插入代码片
总结
若干总结。
标签:相等,++,next,算法,prelen,KMP,字符串,部分 From: https://blog.csdn.net/qq_43969379/article/details/137591047