KMP算法的核心是构建一个部分匹配表(也称为最长相等前后缀表),该表可以用来确定在不匹配时应该跳到字符串的哪个位置。
对于这个问题,可以构建整个字符串的部分匹配表,然后检查表的最后一个值。
如果该值不为0,并且能被字符串长度减去这个值整除,那么字符串就是由它的一个子串重复构成的。
一、实现 strStr()
题目一:28. 找出字符串中第一个匹配项的下标
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
KMP算法思想
/*
* @lc app=leetcode.cn id=28 lang=cpp
*
* [28] 找出字符串中第一个匹配项的下标
*/
// @lc code=start
class Solution {
public:
int strStr(string haystack, string needle) {
if (needle.empty()) return 0;
if (haystack.empty()) return -1;
vector<int> lps = computeLPSArray(needle);
int i = 0;
int j = 0;
while (i < haystack.size()) {
if (haystack[i] == needle[j]) {
i++;
j++;
}
if (j == needle.size()) {
return i - j;
} else if (i < haystack.size() && haystack[i] != needle[j]) {
if (j != 0) {
j = lps[j - 1];
} else {
i++;
}
}
}
return -1;
}
private:
vector<int> computeLPSArray(const string& pattern) {
vector<int> lps(pattern.size(), 0);
int length = 0;
int i = 1;
while (i < pattern.size()) {
if (pattern[i] == pattern[length]) {
length++;
lps[i] = length;
i++;
} else {
if (length != 0) {
length = lps[length - 1];
} else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
};
// @lc code=end
二、 重复的子字符串
题目一:459. 重复的子字符串
给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。
computeLPSArray
函数用于构建字符串的部分匹配表。然后在
repeatedSubstringPattern
函数中,检查这个表的最后一个元素是否满足特定条件,来确定字符串是否由一个重复的子字符串构成。如果这个值不为0,并且字符串长度可以被字符串长度减去这个值整除,那么这个字符串就是由一个子字符串重复多次构成的。
/*
* @lc app=leetcode.cn id=459 lang=cpp
*
* [459] 重复的子字符串
*/
// @lc code=start
class Solution {
public:
bool repeatedSubstringPattern(string s) {
vector<int> lps = computeLPSArray(s);
int n = s.size();
int len = lps[n - 1];
return len != 0 && n % (n - len) == 0;
}
private:
vector<int> computeLPSArray(const string& pattern) {
int n = pattern.size();
vector<int> lps(n, 0);
int len = 0;
int i = 1;
while (i < n) {
if (pattern[i] == pattern[len]) {
len++;
lps[i] = len;
i++;
} else {
if (len != 0) {
len = lps[len - 1];
} else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
};
// @lc code=end