前言:kmp算法
今天又温习了一遍kmp算法(为什么自己学一次忘一次呢。。。)
求next数组有4个步骤:
1.初始化next数组
2.处理前后缀不相同的情况
3.处理前后缀相同的情况
4.更新next数组
我发现我之前手写kmp数组的时候好像一直有一个错误,不知道是不是因为听的网课对模式串作了特殊处理的缘故;例如对于aabaaab字符串,默认next[0] = 0 ,是因为对于‘a’,没有前后缀;
aabaaab
0
然后填next[1]的时候,应该直接看“aa”,所以next[1] = 1;之前一直以为不能算上当前字母。。。
28.找出字符串中第一个匹配项的下标
题目内容:给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
我的代码:
class Solution {
public:
void get_next(vector<int>& next, string s)
{
next[0] = 0;
int i = 1, j = 0; //i为后缀末尾,j为前缀末尾
for( ; i < s.size(); i++) {
while((s[i] != s[j]) && j > 0) {
j = next[j - 1];
}
if(s[i] == s[j]) {
j++;
}
next[i] = j;
}
}
int strStr(string haystack, string needle) {
if(needle.size() == 0) return -1;
vector<int> next(needle.size(), 0);
get_next(next, needle);
int i = 0, j = 0;
for( ; i < haystack.size(); i++) {
while((haystack[i] != needle[j]) && j > 0) {
j = next[j - 1];
}
if(haystack[i] == needle[j]) {
j++;
}
if(j == needle.size()) {
return (i - j + 1);
}
}
return -1;
}
};
反思:一道很经典的kmp算法题了。求next数组的时候,要注意,当前后缀不相等时,前缀末尾j要持续回退至0或回退至前后缀相等,这样才能得到正确的next[i]的值;在正式求下标的时候也是同理,两字符不相等时,j一直回退到头头或者回退至两字符相等,这样才能继续判断;返回下标时注意不直接返回i,因为i此时已经指向了子字符串的末尾,而题目要求的是子字符串在主串中出现的第一个下标,因此还要再减j的下标,由于此时j已经走到了子串的外面一个,因此还要再+1。
感觉自己对kmp算法运行过程以及为什么这么写还不是很懂,还需要多模拟几次代码运行过程多练练题。
459.重复的子字符串
题目内容:给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。
掐头去尾法代码:
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string s1 = s + s;
s1.erase(s1.begin());
s1.erase(s1.end() - 1);
if(s1.find(s) != string :: npos) return true;
return false;
}
};
思路:如果一个字符串是由一个子串重复多次构成的,那么它复制一遍后,中间一定还能再找到一个子串,但是为了防止找到的子串就是由原来子串拼接而来的子串,需要对复制后的字符串掐头去尾。
kmp算法版先欠着吧,今晚感觉脑容量爆炸了。QAQ