28. 实现 strStr()
题目
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1: 输入: haystack = "hello", needle = "ll" 输出: 2
示例 2: 输入: haystack = "aaaaa", needle = "bba" 输出: -1
思路
这道题目其实质是考察KMP经典算法的应用。
所以主要在于理解KMP算法的思想及实现。
KMP名字由来,他的三位发明者的首字母:Knuth,Morris和Pratt。
KMP核心思想:当出现字符串不匹配时,回退到已经匹配过得部分字符开始匹配,避免每次从头匹配,从而大大降低了时间复杂度。
KMP中的一些关键概念
前缀:是指不包含最后一个字符的所有以第一个字符开头的连续子串;
后缀:是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
前缀表:前缀表就是记录模式串的所有字串的最长相等前缀后缀的长度数组。
模式串与前缀表对应位置的数字表示的就是:下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。
有了以上概念就能利用前缀表来实现字符串的匹配了。
关键在于如何实现next数组(也就是构建前缀表):
有三种方式:
1.next=前缀表
2.next = 前缀表所有元素-1
3.next = 前缀表整体右移1位。
代码实现
采用1next = 前缀表的方式
class Solution {
//前缀表(不减一)Java实现
public int strStr(String haystack, String needle) {
if (needle.length() == 0) return 0;
int[] next = new int[needle.length()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.length(); i++) {
while (j > 0 && needle.charAt(j) != haystack.charAt(i))
j = next[j - 1];
if (needle.charAt(j) == haystack.charAt(i))
j++;
if (j == needle.length())
return i - needle.length() + 1;
}
return -1;
}
private void getNext(int[] next, String s) {
int j = 0;
next[0] = 0;
for (int i = 1; i < s.length(); i++) {
while (j > 0 && s.charAt(j) != s.charAt(i))
j = next[j - 1];
if (s.charAt(j) == s.charAt(i))
j++;
next[i] = j;
}
}
}