实现strStr()
知识点
-
KMP(Knuth-Morris-Pratt)算法是一种用于字符串匹配的高效算法。其原理基于字符串匹配时的特性,通过预处理模式字符串(待匹配字符串)的信息,避免在匹配过程中重复比较已经匹配过的部分。
-
前缀表记录了模式字符串中最长相同前后缀的长度
前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串。
后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
最长相同前后缀的长度:
举一个例子“ABABBABC”
-
A -> 0
-
AB -> 0
-
ABA -> 1
-
ABAB -> 2
-
ABABB -> 0
-
ABABBA->0
-
ABABBAB->2
-
ABABBABC->0
再举个栗子“aabaaf”
-
a->0
-
aa->1
-
aab->0
-
aaba->1
-
aabaa->2
-
aabaaf->0
-
-
next 数组 其实就是前缀表的不同表现形式,主流的写法有三种:
拿“aabaaf”来说,需要找到aabaabaaf的匹配下标
第一种next数组表示方式为[0, 1, 0, 1, 2, 0], 当他遍历到f的时候发现f和b有冲突,那么找到f对应的前缀表位置的前一位的值为2,那么之前回退到前缀表下标为2的地方。
第二种next数组表示方式为[-1, 0, 1, 0, 1, 2],当他遍历到f的时候发现f和b有冲突,那么找到f对应的前缀表位置的值为2,那么之前回退到前缀表下标为2的地方。
第三种next数组表示方式为[-1, 0, -1, 0, 1, -1],当他遍历到f的时候发现f和b有冲突,那么找到f对应的前缀表位置的前一位的值为1,加1之后,那么之前回退到前缀表下标为2的地方。
-
难点:next 数组怎么写
我们就看第一种 next 数组的写法
-
初始化
-
前后缀不相等的情况
-
前后缀相等的情况
-
更新 next 数组
/* i:表示后缀末尾;j表示前缀末尾(也表示冲突返回的下标位置)*/ // 初始化 int j = 0; next[0] = 0; for(int i = 1; i < s.size(); i++){ // 前后缀不相等的情况, 根据不变性原理,j也需要回退到j对应的前一位的值对应的下标值的位置 while(j > 0 && s[i] != s[j]){ j = next[j - 1]; } // 前后缀相等的情况 if(s[i] == s[j]){ // 更新next数组 next[i] = j++; } }
-
题目
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)
题解1:暴力解法
class Solution {
public:
int strStr(string haystack, string needle) {
for (int i = 0; i + needle.size() <= haystack.size(); i++) {//i + needle.size() <= haystack.size()
if (haystack[i] == needle[0]) {
bool flag = true;
int j = needle.size() - 1;
for (; j >= 0; j--) {
if (haystack[i + j] != needle[j])
{
flag = false;
break;
}
}
if(flag ){ // 善用flag
return i;
}
}
}
return -1;
}
};
题解2:KMP解法
class Solution {
public:
void getNext(int* next, const string& s){
int j = 0;
next[0] = 0;
for(int i = 1; i < s.size(); i++){
while(j > 0 && s[i] != s[j]){
j = next[j - 1];
}
if(s[i] == s[j]){
j++;
}
next[i] = j;
}
}
int strStr(string haystack, string needle) {
if(needle.size() == 0) return 0;
int next[needle.size()];
getNext(next, needle);
int j = 0;
for(int i = 0; i < haystack.size(); i++){
while(j > 0 && haystack[i] != needle[j]){
j = next[j - 1];
}
if(haystack[i] == needle[j]){
j++;
}
if(j == needle.size()){
return (i - needle.size() + 1);
}
}
return -1;
}
};