leetcode-28-实现 strStr() 函数(KMP)
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。
查看视频
油管阿三哥讲KMP查找算法,中英文字幕,人工翻译,简单易懂
帮你把KMP算法学个通透!(理论篇)
1. 实现前缀表
/**
* 前缀表是用来回退的,记录了当模式串与文本串不匹配时,模式串应该从哪里重新匹配。
* 前缀表具有告诉我们当前位置匹配失败,跳到之前匹配过的地方的能力。
*
* 模式串与前缀表对应位置的数字表示的就是:下标i之前(包括i)的字符串中,有多大长度的相同前后缀。
*
* next数组就可以是前缀表,但是很多实现都是把前缀表统一减一(或者右移一位,初始位置为-1)之后作为next数组。
* 这并不涉及到KMP的原理,而是具体实现方式不同嗯,next数组即可以就是前缀表,也可以是前缀表统一减一(或者右移一位,初始位置为-1)。
*
* 下面的 kmpNext 方法是:next数组就是前缀表。
*
* @param pattern
* @return
*/
private int[] kmpNext(String pattern) {
int len = pattern.length();
// 初始化前缀表,与模式串长度相同
int[] next = new int[len];
// 规定前缀表第一个元素值为0
next[0] = 0;
// i指向后缀终止位置,index指向前缀终止位置即前缀的长度
int i = 1, index = 0;
while (i < len) {
// 如果在pattern上位置i和位置index上的字符相同时,把 index(前缀的长度)+1 赋值给next[i],index和i向前移动一位
if (pattern.charAt(i) == pattern.charAt(index)) {
next[i] = index + 1;
index++;
i++;
} else {
// 如果在pattern上位置i和位置index上的字符不相同时,把前缀的位置index移动到next[index - 1]
if (index != 0) {
index = next[index - 1];
// 如果在pattern上位置i和位置index上的字符不相同时,且已经把前缀的位置index移动到next数组第0位置上还是不相等,
// 就把next数组位置i上赋值为0,并把i往前移动一位
} else {
next[i] = 0;
i++;
}
}
}
return next;
}
2. 实现KMP搜索
private int kmpSerach(String haystack, String needle) {
int[] next = kmpNext1(needle);
// hi,ni两个指针分别指向文本串和模式串的开头
int hi = 0, ni = 0;
while (hi < haystack.length() && ni < needle.length()) {
// 如果文本串和模式串分别在hi和ni上元素相同,把hi和ni同时往前移动一位
if (haystack.charAt(hi) == needle.charAt(ni)) {
hi++;
ni++;
} else { // 当模式串与文本串不等时
if (ni == 0) {
// 当模式串第一个位置字符与文本串不等时,文本串指针向前移动一位
hi++;
} else {
// 把模式串按照next数组向前回溯
ni = next[ni - 1];
}
}
}
if (ni == needle.length()) {
return hi - ni;
}
return -1;
}