1、实现 strStr()
直接使用前缀表的方法(更推荐):
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
void getNext(int *next, const string &s) {
//初始化
int j = 0;
next[0] = 0;
/* j指向前缀末尾,同时也是i之前(包括i)的子串的最长相等前后缀的长度
* i指向后缀末尾 */
for (int i = 1; i < s.size(); ++i) {
while (j > 0 && s[i] != s[j]) { //s[i]和s[j]不相等的情况,注意这里可能不止回退一次,要用while
j = next[j - 1]; //这一步是KMP算法的精髓
}
if (s[i] == s[j]) { //s[i]和s[j]相等的情况
j++;
}
next[i] = j; //赋值next数组
}
}
int strStr(string haystack, string needle) {
if (needle.empty())
return 0;
vector<int> next(needle.size());
getNext(&next[0], needle); //获得next数组
/* j指向模式串起始位置
* i指向文本串起始位置 */
int j = 0;
for (int i = 0; i < haystack.size(); ++i) { //遍历文本串
while (j > 0 && haystack[i] != needle[j]) { //不相等的情况,注意这里也可能不止回退一次,也要用while
j = next[j - 1];
}
if (haystack[i] == needle[j]) { //相等的情况
j++;
}
if (j == needle.size()) {
return (i - needle.size() + 1);
}
}
return -1;
}
};
int main() {
string s1 = "aabaabaaf";
string s2 = "aabaaf";
Solution solution;
cout << solution.strStr(s1, s2) << endl;
//打印next数组
vector<int> next(s2.size());
solution.getNext(&next[0], s2);
for (auto ele: next) {
cout << ele << " ";
}
}
2、重复的子字符串
直接使用前缀表:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
void getNext(int *next, const string &s) {
next[0] = 0;
int j = 0;
for (int i = 1; i < s.size(); i++) {
while (j > 0 && s[i] != s[j]) {
j = next[j - 1];
}
if (s[i] == s[j]) {
j++;
}
next[i] = j;
}
}
bool repeatedSubstringPattern(const string &s) {
if (s.empty())
return false;
int next[s.size()];
getNext(next, s);
int len = s.size();
if (next[len - 1] != 0 && len % (len - next[len - 1]) == 0) {
return true;
}
return false;
}
};
int main() {
string s = "aba";
Solution solution;
cout << solution.repeatedSubstringPattern(s) << endl;
//打印next数组
vector<int> next(s.size());
solution.getNext(&next[0], s);
for (auto ele: next) {
cout << ele << " ";
}
}