28. 实现 strStr()
思路:没什么好说的,kmp算法重中之重,应该反复思考和琢磨至少一种kmp的next数组的获取函数,建议直接看carl的讲解视频。目前我都采用的是原next数组的方法,毕竟贪多嚼不烂,二刷建议实现所有方法。
#include <iostream>
using namespace std;
class Solution {
public:
void getNext(int* next, const string& s) {
int j = 0;
next[0] = 0;
for (int i = 1; i < s.size(); ++i) {
// 不相等的情况,j往前回跳
while (j > 0 && s[i] != s[j]) {
j = next[j - 1];
}
// 相等的情况,next数组更新
if (s[i] == s[j]) {
j++;
}
next[i] = j;
}
}
// 时间复杂度: O(n + m)
// 空间复杂度: O(m)
int strStr(string haystack, string needle) {
if (needle.size() == 0) {
return 0;
}
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 = next[j - 1];
}
if (haystack[i] == needle[j]) {
// 检查 haystack 和 needle 在位置 i 和 j 处的当前字符是否相等。如果相等,它将 j 增加1,以移动到 needle 中的下一个字符。
j++;
}
if (j == needle.size()) {
// 检查 j 是否已经到达 needle 字符串的末尾。如果是,表示在 haystack 中找到了完全匹配,因此返回匹配的起始索引 (i - needle.size() + 1)
return (i - needle.size() + 1);
}
}
// 走到此行说明未找到匹配子串,返回-1
return -1;
}
};
459.重复的子字符串
思路:属于kmp算法的应用之一。
#include <iostream>
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(string s) {
if (s.size() == 0) {
return false;
}
int next[s.size()];
getNext(next, s);
int len = s.size();
/**
在KMP算法中,next数组的含义是在字符串中每个位置i之前的最长相同前缀后缀的长度。如果字符串可以由重复的子串构成,那么最后一个位置的next值就是子串的长度。
假设字符串s可以由重复的子串构成,且子串的长度为len - next[len - 1]。那么字符串s的长度len必然可以被(len - next[len - 1])整除,因为每个子串的长度都是(len - next[len - 1])。
另外,如果字符串s可以由重复的子串构成,那么next数组的最后一个元素next[len - 1]一定不为零。因为如果为零,说明整个字符串s没有相同的前缀和后缀,即没有重复的子串。
因此,满足next[len - 1]不为零,并且len能够被(len - next[len - 1])整除,可以判断字符串s是否可以由重复的子串构成。*/
if (next[len - 1] != 0 && len % (len - (next[len - 1])) == 0) {
return true;
}
return false;
}
};