【LeetCode】28.实现strStr()(KMP算法)
题目链接
28. 实现 strStr()
题目描述
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = "hello", needle = "ll"
输出: 2
示例 2:
输入: haystack = "aaaaa", needle = "bba"
输出: -1
解题思路
1.Java内置函数
2.BF暴力法
3.滑动窗口
利用substring函数从haystack依次截取与needle字符串相同长度的字符串,两者进行比较即可
4.KMP算法
KMP算法的核心就在于求解模式串的最长公共前后缀,且next数组中next[0]=-1,next[1]=0是确定的,next数组的意义在于当模式串当前字符与匹配串不匹配时,next数组值就是模式串指针的下一个位置,而不是和暴力方法一样,每次都从头开始!
AC代码
1.Java内置函数
String haystack = "hellowordllo";
String needle = "llo";
System.out.println(haystack.lastIndexOf(needle));//9
System.out.println(haystack.indexOf(needle));//2
System.out.println(haystack.indexOf(needle,3));//9
a.indexOf(String s) //从字符串a开始从前往后找到第一个与字符s匹配的子串,找到就返回匹配的子串的下标,否则返回-1
a.indexOf(String s,int Fromindex)//从字符串a第Fromidnex个元素开始从前往后找到第一个与字符s匹配的子串,找到就返回匹配的子串的下标,否则返回-1
a.lastIndexOf(String s)//从后往前找
2.BF暴力法(超时)
class Solution {
public int strStr(String haystack, String needle) {
if(haystack.equals(needle)) return 0;
if(haystack.length() < needle.length()) return -1;
for(int i = 0; i < haystack.length(); i++){
int index = i;
int cnt = 0;
for(int j = 0; j < needle.length(); j++){
if(index < haystack.length() && needle.charAt(j) == haystack.charAt(index)){
index++;
cnt++;
}
else break;
}
if(cnt == needle.length()) return i;
}
return -1;
}
}
3.滑动窗口
class Solution {
public int strStr(String haystack, String needle) {
if(haystack.equals(needle)) return 0;
if(haystack.length() < needle.length()) return -1;
int h_len = haystack.length();
int n_len = needle.length();
for(int i = 0; i <= h_len-n_len; i++){
String s = haystack.substring(i,i+n_len);
if(s.equals(needle)) return i;
}
return -1;
}
}
4.KMP算法
//KMP算法的核心在于求解next数组
class Solution {
//next数组计算方法1
int[] getnext(String needle){
int[] next = new int[needle.length()];
next[0] = -1;
int l = -1;
int index = 0;
while(index < needle.length() - 1){
if(l == -1 || needle.charAt(l) == needle.charAt(index)){
l++;
index++;
next[index] = l;
}else l = next[l];
}
return next;
}
//next数组计算方法2(个人觉得这个更好理解)
int[] getnext(String needle){
int[] next = new int[needle.length()+1];//避免出现needle = "a"的情况,
//如果needle=”a",那next[1]属于非法访问,所以next数组大小为needle.length()+1;
next[0] = -1;
next[1] = 0;
int k = 0;
int i = 2
while(i < needle.length()){
if(needle.charAt(i-1)==needle.charAt(k)){
k++;
next[i] = k;
i++;
}else if(k == 0){//needle=“abcdefg",针对此种特殊情况
next[i] = 0;
i++;
}else{
k = next[k];//有点类似与回溯的味道,不理解就强行背诵。
}
}
return next;
}
//next数组计算方法3(暴力法,不过一般都会超时,所以了解一下就好)
int[] getnext(String needle){
int[] next = new int[needle.length()+1];
next[0] = -1;
next[1] = 0;
for(int i = 2; i < needle.length(); i++){
for(int j = 1; j < i; j++){ //j表示最长公共前后缀的长度
if(needle.substring(0,j).equals(needle.substring(i-j,i-j+j))){
next[i] = j;
}
}
}
return next;
}
public int strStr(String haystack, String needle) {
if(haystack.length() == 0 && needle.length() == 0) return 0;
if(haystack.length() == 0) return -1;
if(needle.length() == 0) return 0;
int h_len = haystack.length();
int n_len = needle.length();
int h_index = 0;
int n_index = 0;
int[] next = getnext(needle);
while(h_index < h_len){
if(haystack.charAt(h_index) == needle.charAt(n_index)){
h_index++;
n_index++;
}else{
if(n_index == 0){//两个字符串首个元素不同,那匹配串指针肯定要加1呀
h_index++;
}else{
n_index = next[n_index];
}
}
//当模式串指针到模式串末尾,证明匹配成功
if(n_index == needle.length()) return h_index-n_index;
}
return -1;
}
}