力扣459:重复的子字符串
【描述】
给出一个非空字符串,判断该字符串是否由子字符串重复组成。
例:
输入:“abab”
输出:“true”
输入:“abcd”
输出:“false”
kmp算法介绍
这也是一道可以用kmp算法解决的题目。为什么这么说?
这涉及到kmp算法中next数组的定义了:next 数组记录的是最长相等前后缀的长度。
最长相等前后缀的长度为 next[next.size() - 1],
如果一个长度为 n 的字符串 s 可以由它的一个长度为 n’ 的子串 s’ 重复多次构成,那么:
- n 一定是 n’ 的倍数;
- s’ 一定是 s 的前缀;
由于 next[n−1] 表示 s 具有长度为 next[n−1]+1 的完全相同的(且最长的)前缀和后缀。那么对于满足题目要求的字符串,一定有 n % (n - (next[n - 1])) == 0;
对于不满足题目要求的字符串,n 一定不是 n − next[n − 1] 的倍数。
因此,我们在预处理出 next 数组后,只需要判断 n 是否为 n − next[n − 1] 的倍数即可。
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
/*
* Author: 酒馆店小二
* Description: 459.重复的子字符串
* Date: 2022-02-21 10:25:16 星期一
* FileName: leetcode459.cpp
* Location: D:\VSCODE_CPP\algorithm\kmp\leetcode459.cpp
*/
vector<int> kmpNext(const string &substr) { // KMP next 数组
int n = substr.size();
vector<int> next(n);
next[0] = 0;
for (int i = 1, j = 0; i < n; ++i) { // 注意 i 从1开始
// 要保证 j > 0,因为会用到 j - 1 做下标
while (j > 0 && substr[i] != substr[j]) { // 前后缀不相同
j = next[j - 1]; // 向前回退
}
if (substr[i] == substr[j]) { // 找到相同的前后缀
j++;
}
next[i] = j; // 将 j(前缀的长度) 赋给next[i]
}
return next;
}
bool repeatedSubstringPattern(string s) {
int len = s.size();
if (len == 0) {
return false;
}
vector<int> next(len);
next = kmpNext(s);
if (next[len - 1] != 0 && len % (len - (next[len - 1])) == 0) {
return true;
}
return false;
}
int main(int argc, char* argv[]){
string res = "abcabc";
string test = "bnmk";
bool ans = repeatedSubstringPattern(res);
bool so = repeatedSubstringPattern(test);
cout << ans << ", " << so << endl;
return 0;
}
修改于:2022.02.21
欲买桂花同载酒,终不似,少年游。