Leetcode 实现strStr函数(KMP)
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = “hello”, needle = “ll”
输出: 2
示例 2:
输入: haystack = “aaaaa”, needle = “bba”
输出: -1
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
class Solution {
public int strStr(String haystack, String needle) {
int[] next = Getnext(needle);
if(haystack == null) return -1;//剪枝
if(next[0] == -1||needle == null) return 0;//leetcode用例 "","",进行输出
int j = 0;
int i = 0;
while(i < haystack.length()){
if(haystack.charAt(i) == needle.charAt(j)){//如果对比字符相同haystack和needle的指针向后移
i++;
j++;
}
if(j == needle.length()){
return i - j;
}
else if(i < haystack.length()&&haystack.charAt(i) != needle.charAt(j)){//字符不匹配
if(j != 0){//needle的指向未在首字符处,就通过next数组的字符串前后缀匹配,向前移动,进行下一次的字符匹配
j = next[j - 1];
}
else//没有公共前缀,直接让haystack的字符与needle的首字符对比
i++;
}
}
return -1;
}
/*
next数组,寻找needle的公共前后缀,在某个字符处不匹配时,
就找出它之前的字符串的最大公共前后缀,在haystack与needle
对比时,将needle的指向移向公共前缀后的一个字符,haystack的
指向位置不变,两个字符再进行对比。
*/
public int[] Getnext(String needle){
if(needle.length() > 0){//防止空字符串
int[] next = new int[needle.length()];
next[0] = 0;//人为设置,开头未匹配,就从needle的首字符对比
int j = 0, i = 1;//两个指向来判断是否是公共前后缀
while(i < needle.length()){
/*
如果两个字符相同,i,j都向后移动next[i]存储
在needle.charAt(i)处不匹配时,needle不用回溯
通过next[i]来定位needle在下一次对比时指向
(记录最大公共前缀后的一个字符的位置)
*/
if(needle.charAt(i) == needle.charAt(j)){
j++;
next[i] = j;
i++;
}
else{
/*
如果j指向在needle的首字符,i就往后找公共前后缀
在进行对比时,此处不匹配的话,就从needle的首字符对比
*/
if(j == 0){
next[i] = 0;
i++;
}
else{
//如果在此处不一样就看之前的字符串的
//最大公共前后缀
j = next[j - 1];
}
}
}
return next;
}
int[] next = {-1};
return next;
}
}
执行结果:
通过
显示详情
执行用时:11 ms, 在所有 Java 提交中击败了7.99% 的用户
内存消耗:39.8 MB, 在所有 Java 提交中击败了21.59% 的用户
总结
实现kmp算法时,先找needle的next数组,找各个字符与之前字符串的最大公共前后缀,可以不用每次都必须进行回溯,最后进行haystack与needle的字符匹配。kmp算法的优势就是每次匹配不成功时needle不用每次都回溯至首字符,减少比较次数。
主要参考了题解中带佬的讲解,带佬的题解地址,其中附加的三哥讲解的next数组挺好的
有什么不对的地方,还望在评论区指出。