这一题 第一反应是 用map 或者栈
但是仔细想想后觉得太麻烦了
于是选用了双指针的方法
class Solution {
public:
int strStr(string haystack, string needle) {
int hay = 0;
int nee = 0;
int ans = -1;
for (; hay < haystack.size(); ++hay)
{
if (haystack[hay] == needle[nee])
{
int tem = hay;
for (; nee < needle.size(); ++nee)
{
if (haystack[hay++] != needle[nee])
{
nee = 0;
hay = tem;
break;
}
if (nee == needle.size() - 1)
ans = tem;
}
}
}
return ans == -1 ? -1 : ans;
}
};
代码随想录中讲到了 KMP 学习一下
KMP有什么用:KMP的主要思想是出现字符串不匹配时,可以知道一部分已经匹配的内容,避免再次匹配
什么是前缀表:前缀表是用来回退的,记录了模式串与字符串不匹配时,应该从哪里开始重新匹配模式串
记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。
为什么要使用前缀表: 找到最长相等的前缀和后缀后, 匹配不同的位置是后缀的后面, 那我们找到前缀之后的位置进行重新匹配就好了 因为 前缀和后缀是一样的啊
如何计算前缀表:下标i之前(包括i) 有多少个长度相同的前缀后缀
找到不匹配的位置后, 应该查前一个元素的前缀表, 移动到指定的索引处
next数组:可以是前缀表 也可以是前缀表统一减1 影响的是代码怎么写
构造next数组(计算前缀表):
void getNext(int *next, const string &s)
{
}
初始化
int j = 0;
next[0] = 0;
定义指针j 指向前缀末尾 next进行赋值 next[i] 表示i(包括i)之前最长相等的前后缀长度
当前缀和后缀不同的情况
个人理解 再把他们看作一种比较, 只要不同就回退到前一位的next对应处
while(j > 0 && s[j] != s[i]
{
j = next[j - 1];
}
当前后缀相同的情况
if (s[j] == s[i]
{
++j;
next[i] = j;
}
完整代码
void getNext(int *next, string &s)
{
int j = 0;
next[0] = 0;
for (int i = 1; i < s.size();++i)
{
while (j > 0 && s[j] != s[i])
j = next[j - 1];
if (s[j] == s[i])
++j;
next[i] = j;
}
}
运用上述代码 完成题目
int strStr(string haystack, string needle) {
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;
}
KMP还是比较难理解的 虽然现在能写出来了 不代表 过几天还会 过段时间再回头重做····