字符串经典题目:
给定一个非空的字符串,判断他是否由一个子串重复多次构成,给定的字符只有小写英文字母,且长度不超过10000.
示例 1:
直接记录我学习理解的kmp算法的一种,主要掌握前缀表(next数组)的写,以及匹配子串的思想。
- 输入: "abab"
- 输出: True
- 解释: 可由子字符串 "ab" 重复两次构成。
示例 2:
- 输入: "aba"
- 输出: False
通过计算
next
数组,我们可以确定字符串的前缀和后缀的最长公共元素。(也就是前缀和)不必纠结这个名词。如果字符串的最后一个字符的next
值不为0,并且字符串长度能够被去掉这部分公共元素后的长度整除,那么字符串就是重复子串模式。
主要学习理解的是next
数组:
next数组是KMP(Knuth-Morris-Pratt)算法中用于模式匹配的核心部分。next
数组的目的是帮助算法在不匹配时能够“跳跃”到正确的位置,而不是简单地从当前位置重新开始匹配。
next
数组的含义
next
数组的每个元素next[i]
表示字符串的前i
个字符中,最长的相同前缀和后缀的长度。换句话说,它表示在字符串的第i
个位置发生不匹配时,我们应该将模式字符串的开始位置回退到哪个位置,以便继续匹配。
-
初始化:
next[0] = 0;
:字符串的第一个字符没有前缀,因此最长的相同前缀和后缀长度为0。
-
遍历字符串:
- 通过一个循环遍历字符串的每个字符,从第二个字符开始(索引为1)。
-
处理不匹配情况:
- 当当前字符不匹配时(即
s[i] != s[j]
),我们需要找到一个更短的前缀,使得这个前缀和当前位置之后的字符串有相同的后缀。这是通过回退j
来实现的,即j = next[j-1]
。
- 当当前字符不匹配时(即
-
更新
next
数组:- 如果当前字符匹配(即
s[i] == s[j]
),则增加j
的值,因为此时我们找到了一个更长的相同前缀和后缀。 - 更新
next[i]
为j
的值,表示在第i
个位置,最长的相同前缀和后缀的长度。
- 如果当前字符匹配(即
理解
next
数组的构建过程对于理解KMP算法至关重要,因为它是算法能够高效运行的关键。
代码:
class Solution {
public:
void getnext( int *next , 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();
if(next[len-1] != 0 && len %(len-(next[len-1]))==0)
{
return true;
}
return false;
}
};