重复的子字符串
碰到一道算法题,可以按照以下思考流程进行,避免没有思路。
一.暴力遍历枚举 -> 2.模拟操作 ->3.常用的算法技巧或题型,比如双指针,滑动窗口,动态规划,回溯算法之类
通常最后的解法都是在暴力遍历或枚举或模拟操作解决的过程中,发现问题的内在性质,从而找到更好的方法。
但是除了数学建模这类的问题,要使用数学知识,其他的本质还是穷举出所有的结果,只不过动态规划发现了最优子结构,回溯进行了剪枝,不必列出所有的结果,不重复,不遗漏。
1.暴力枚举
枚举子字串长度分别为1,2,3,......, str.size() / 2,按子串长度区间去匹配,判断是否能构成字串str。
例如:abcabcabc,枚举子串长度为2时,每个i, str[i] == str[i - 2],如果不相等,说明不能组成该字串。
参考代码:
class Solution {
public:
bool repeatedSubstringPattern(string s) {
for (int i = 1; i * 2 <= s.size(); ++i) {//遍历所有可能的子串长度
if (s.size() % i == 0) {//判断是否能组成该字串
bool matchFlag = true;
for (int j = i; j < s.size(); ++j) {
if (s[j] != s[j - i]) {
matchFlag = false;
break;
}
}
if (matchFlag)
return true;
}
}
return false;
}
};
只要掌握暴力枚举即可,下面的解法可能想不到,可以死记硬背下来,当作结论使用。
2.根据重复子串组成字串的性质:假设字串为s,那么ss字串去除首字母和尾字母的字串str,如果str中包含s,那么s是由自身某个子串重复组成的。大家可以自行搜索证明。
参考代码:使用Kmp算法进行子串匹配
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string str = s + s;
//构建next数组
vector<int> next(s.size(), 0);
for(int i = 1, j = 0; i < s.size(); ++i){
while(j > 0 && s[j] != s[i]){
j = next[j - 1];
}
if(s[j] == s[i]){
++j;
}
next[i] = j;
}
//匹配子串
for(int i = 1, j = 0; i < str.size() - 1; ++i){
while(j > 0 && str[i] != s[j]){
j = next[j - 1];
}
if(str[i] == s[j]){
j++;
}
if(j == s.size())
return true;
}
return false;
}
};