一:题目
二:上码
class Solution {
public:
/**
思路:
1.KMP算法,主要处理的是字符串匹配的问题
2.这里边需要用到next数组 也就是前缀表;那么我们为什么要用前缀表呢,当我们进行匹配字符的时候
发现匹配到不相同的字符的时候,那么我们就需要在匹配字符串中查询前一个字符所对应的在
前缀表表中的数值,根据数值找到对应的字符 让其重新作为匹配字符串的开始匹配的位置。
3.为什么使用next数组可以告诉我们匹配失败之后跳到哪里重新匹配
因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,
那么我们找到与其相同的前缀的后面从新匹配就可以了。
4.那么我们怎么求取前缀表呢?首先先明白何为前缀、后缀、最长公共前后缀
<1>:前缀:前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串
eg:aabaaf
其前缀可以是:a
aa
aab
aaba
aabaa
<2>:后缀:后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串
eg:aabaaf
其后缀可以是:f
af
aaf
baaf
abaaf
<3>:最长公共前后缀:也就是给定一个字符串,我们找到其前缀和后缀相等的最长部分
eg:字符串 公共的部分 公共部分的长度
a 0
aa a 1
aab 0
aaba a 1
aabaa aa 2
aabaaf 0
<4>:根据<3>求出的公共部分我们就可以求出next数组(前缀表)
字符串: a a b a a f
下 标: 0 1 2 3 4 5
next[]: 0 1 0 1 2 0
4.如何用next数组来进行匹配呢?
被匹配的字符串:aabaabaaf
匹配的字符串:aabaaf
当匹配到f的时候发现f和b此时不匹配,那 么我们就需要查询匹配字符串的前一个字符所对应的next
数组中的数值,然后再从该数值所对应的字符开始匹配。回归示例就是我们的f前面的字符
a对应的next数组中的数值是2,那么我们就从字符串的2位置对应的字符开始匹配也就是b
*/
//求出模式串的前缀表 那么我们首先要明白这个函数的主体作用是干啥的
//我们是比较一个字符串当中的子串的前缀和后缀 来求出该子串对应的最长相同的前后缀
//比如: aabaaf的子串 aabaa 该子串对应的next[4] = 2 表示最长公共前后缀是2
//还有需要注意的是我们的前缀末尾下标是和后缀的末尾下标是一块往后移动的
void getNext(int *next,string s) {
int j = 0;//前缀末尾的部分
next[0] = 0;//字符串长度为0的话,那么的话最长相等前后缀也是0
for (int i = 1; i < s.size(); i++) {//i表示的后缀表的末尾部分
while (j > 0 && s[i] != s[j]) {//处理前缀跟后缀不相同的部分。
j = next[j-1];//将j的上一个坐标对应的最长公共前后缀 赋值给j aabcaaf中遇见f时
//我们找next[j-1] = 2,也就是找到下标b来进行匹配
}
if (s[i] == s[j]) {//前缀跟后缀相同的时
j++;
}
next[i] = j;//这个j的长度也就是最长公共前后缀
}
}
int strStr(string haystack, string needle) {
if (needle.size() == 0) return 0;
int next[needle.size()];
getNext(next,needle);
//在 h 中 找 n 如果遇见了不相等的字符的话 那么 h中的下标往后移重新匹配字符,如果遇见相等的那就继续
//匹配,但要通过j来记录相同的长度。
int j = 0;//显示我们的被匹配的字符串
for (int i = 0; i < haystack.size(); i++) {//下标从0开始
while (j > 0 && haystack[i] != needle[j]) {//当遇见字符不相等的时候
j = next[j-1];
}
if (haystack[i] == needle[j]) j++;
if (j == needle.size()) {
return (i-j+1);//hello 和 ll (3-2+1 = 2)
}
}
return -1;
}
};