首先具体KMP算法理论在上面的博客中,不过该博客我当初写的时候并没有了解next数组实现的过程是那样的,所以只介绍了KMP的理论,next理论没有细致的给出
1.实现strStr()
这里我将解释我自己对于next数组的理解
先定个规矩,next[0]为-1
1.因为0位置不需要判断它跟谁一样,其实是一个能表示为初始位置的值就行。
2.但是我们不满足于表示为初始位置,因为我们查下标还要用到,所以可选-1,0这些值。
3.而之所以要选-1,因为我们把一个位置对应的相同前缀串情况,存到后一个位置去了。next有很多实现方式,但是我要实现的是开头为-1。
4.后面一个的next值表示前面的相同前缀串情况。(后续解决) 正因为如此,-1表示前面是空白
再定个规矩,next[1]为0
1.因为1位置起才开始算,1位置前面只有一个符号
2.上面也讲了后面一个的next值表示前面的相同前缀串情况。所以1位置前面就一个数,0位置的字符自己跟自己不用比,因此直接记为0
next数组后一个其实是用来存储某个位置的结果
1.简单说,这个位置的next数值代表前几个数据是对上的(看图很清楚)
此时,应该很清楚,某位置反映前面的相同前缀长了吧!!!
而且更重要的一点是,对上前缀的结果位置的next正好是开头对齐的后一个位置(比如右下角p的next值为2,数组下标2位置前就是对上的前缀)!!![这点是后面实现的核心]
2.所以这次的判断会决定下一次的next结果(核心问题单独讨论)
如何才能让,所谓判断会决定下一次的next结果
1.在循环外,先将0位置next为-1
2.i设置为next的下标,j处理后是填入next数组的数据,我们需要做的就是用i来遍历next,并且将j值赋给next数组。使用while语句,更方便控制。
3.循环开始前的最后准备:由于开始i=0,j就应该是-1,这样就匹配上数组i位置值为j
4.由于一个位置反映前面的情况,我们是由0开始的,那么就是由i定i+1位置的next值。
5.如果j==-1,说明是i是0位置,那么我们要做的就是把1位置的next赋值为0,简单将就是next[++i]=++j;这样i往后走了,j也是i往后走对应的next值
6.此时是最关键的一步
我们的 i 往后走了一步,现在要确定的就是i+1反映的是 i 跟前面内容的关系
假设我们已经得到了很多next值了,其本质我们也清楚了
1.最简单的就是i位置和对应j下标位置的值一样,说明此时最长前缀后面加一个字符,它也是对上的,那么其实++i位置的next等于++j
2.不相等,则更新将j更新为k,因为此时两边是对不上的,那么后面那一串就没有意义了,需要重新和前面的部分对应。但是前面部分我们已经知道情况了,所以j更新到k位置,那么更新后j的k值又会回到上面的判断(判断i+1位置和j对应的k位置到底对不对的上)。如果找不到就循环第二步,找到就走第一步。
class Solution {
public:
void getNext(string& needle,vector<int> &next)
{
next[0]=-1;
int i=0, j=-1;
while(i<needle.size()-1)
{
if(j==-1||needle[i]==needle[j]){
next[++i]=++j;
}
else
{
j=next[j];
}
}
}
int getTarget(string& haystack, string& needle,vector<int> &next)
{
int i=0,j=0;
while(i<haystack.size())
{
if(haystack[i]==needle[j])
{
if(j==needle.size()-1)
return i-j;
i++;
j++;
}
else if(j==0)
{
i++;
}
else
j=next[j];
}
return -1;
}
int strStr(string haystack, string needle) {
vector<int> next(needle.size(),0);
getNext(needle,next);
return getTarget(haystack,needle,next);
}
};
2.重复的子字符串
实现其实很简单,s加成一倍,掐头去尾。如果还能在这个字符串里找到s就说明是重复的,反之不是。
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string tmp(s.begin()+1,s.end());
tmp+=s;
tmp.erase(tmp.size()-1);
cout<<tmp;
if(tmp.find(s)==string::npos)
return false;
return true;
}
};