Practice Day seventeen:Leetcode T 435
由于Day 16我们已经对KMP算法进行了超详细的讲解,虽然有些王婆卖瓜的嫌疑,但我仍认为我没有夸大其词。总而言之,今天我不会讲KMP的原理了,而是讲解实现方法。
我这里还有一份利用周期性实现KMP算法的讲解链接,有兴趣的兄弟姐妹可以看看,也是挺有意思的,我不再对此进行讲解
https://zhuanlan.zhihu.com/p/661673949https://zhuanlan.zhihu.com/p/661673949
今天我们学习另一种KMP实现方法
该方法出自B站up主 NotOnlySuccess
视频链接如下
这位老哥提出了另一种KMP构建法:把模式串链接到主串上,当组合串的某一个元素的next数组记录的步长与模式串长度相同,即为找到了所需字符。
真是一种十分天才的方法,完美的利用了前缀函数的性质。模式串与主串的相接,实现了主串数组局部确立,从而可以使用前缀函数求解。
这里模式串链接到主串上面的时候,需要在模式串后面加一个与模式串无关的字符,以保证没有局部匹配的情况发生。如果你不清楚什么是局部匹配,请移步Day 16进行阅读相关部分。(局部匹配这个词是我造的,我没有在任何一个视频或者讲解中看到对于这种情况的说明,如有雷同,纯属巧合)。
让我们来看看老哥的代码是如何实现的。
1 一些基础的准备工作就不讲解了,该讲的Day 16已经讲解过了
int strStr(string main, string pattern) {
int n = main.size(), m = pattern.size();
string s = pattern + '#' + main;
vector<int> pi(s.size());
2 然后是构造整个组合串的pi数组,返回符合条件对象,找不到就返回-1。
其实这和我们Day 16实现的KMP挺像的,只不过匹配流程直接一步到位了。
这里return i-m*2是因为我们向主串中加入了模式串和一个不相干的字符,所以不用+1,而且由于模式串挤占了位置,所以要减去m*2。
for (int i = 1; i < s.size(); i++) {
int len = pi[i-1];
while (len && s[i] != s[len]) {
len = pi[len - 1];
}
if (s[i] == s[len]) {
pi[i] = len + 1;
if (pi[i] == m) {
return i - m * 2;
}
}
}
return -1;
}
今天的大部分篇幅都在Day 16中讲解,所以今天的实现十分简短。