给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
输入: "abab"
输出: True
解释: 可由子字符串 "ab" 重复两次构成。
示例 2:
输入: "aba"
输出: False
示例 3:
输入: "abcabcabcabc"
输出: True
解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)
解题思路
假设给定字符串s可由一个子串x重复n次构成,即s=nx。
现构造新字符串t=2s,即两个s相加,由于s=nx,则t=2nx。
去掉t的开头与结尾两位,则这两处的子串被破坏掉,此时t中包含2n-2个子串。
由于t中包含2n-2个子串,s中包含n个子串,若t中包含s,则有2n-2>=n,可得n>=2,由此我们可知字符串s可由一个子串x重复至少2次构成,判定为true;反之,若t中不包含s,则有2n-2<n,可得n<2,n只能为1,由此我们可知字符串s=x,假定的子串就为s本身,判定为false。
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string str=s+s;
str=str.substr(1,str.size()-2);
if(str.find(s)==-1)
return false;
return true;
}
};
KMP
class Solution {
public:
int strStr(string haystack, string needle) {
if(!needle.size()) return 0;
if(!haystack.size()) return -1;
//先构造pattern
int j = -1, i = 0;//j在后面,i在前面
vector<int> b(needle.size() + 1);
b[0] = -1;
while(i < needle.size())
{
while(j >= 0 && needle[i] != needle[j]) j = b[j];
b[++i] = ++j;
}
j = 0, i = 0; //j这回是text的, i是pattern的
while(j < haystack.size())
{
while(i >= 0 && needle[i] != haystack[j]) i = b[i];
i++, j++;
if(i == needle.size())
return j - needle.size();
}
return -1;
}
};
基于kmp
class Solution {
public:
vector<int> get_next_arr(const string& str)
{
if (str.size() == 1)
{
return vector<int>{-1};
}
vector<int> next(str.size());
next.at(0) = -1;
next.at(1) = 0;
int i = 2;
int cn = 0;
while (i < next.size())
{
if (str.at(i - 1) == str.at(cn))
{
next.at(i++) = ++cn;
}
else
{
if (cn > 0)
{
cn = next.at(cn);
}
else
{
next.at(i++) = 0;
}
}
}
return next;
}
bool repeatedSubstringPattern(string s) {
if (s.size() < 2)
{
return false;
}
vector<int> next = get_next_arr(s + "#");
//如果是由重复构成,则二倍 或 多倍关系(多倍关系时 前缀、后缀最长匹配有重叠部分)
//如果有重叠部分,字符串由 重叠部分 * n 构成
return next.at(s.size()) * 2 >= s.size() && s.size() % (s.size() - next.at(s.size())) == 0;
}
};
//Following program is a C implementation of the Rabin Karp Algorithm
//given in the CLRS book
#include <stdio.h>
#include <string.h>
//d is the number of characters in input alphabet
#define d 256
//pat -> pattern txt -> text q -> A prime number
void search(char *pat, char *txt, int q)
{
int m = strlen(pat);
int n = strlen(txt);
int i, j;
int p = 0; //hash value for pattern
int t = 0; //hash value for txt
int h = 1;
//the value of h would be "pow(d, m - 1) % q"
for(i = 0; i < m - 1; i++)
{
h = (h * d) % q;
}
//calculate the hash value of pattern and first window of text
for(i = 0; i < m; i++)
{
p = (d * p + pat[i]) % q;
t = (d * t + txt[i]) % q;
}
//slide the pattern over text one by one
for(i = 0; i <= n - m; i++)
{
//check the hash values of current window of text and pattern
//if the hash values match then only check for characters on by one
if(p == t)
{
//check for characters one by one
for(j = 0; j < m; j++)
{
if(txt[i + j] != pat[j])
{
break;
}
}
if(j == m) //found
{
printf("Pattern found at index %d\n", i);
}
}
//calulate hash value for next window of text: remove leading digit
//add trailing digit
if(i < n - m)
{
t = (d * ( t - txt[i] * h) + txt[i + m]) % q;
//we might get negative value of t, converting it to positive
if(t < 0)
{
t = t + q;
}
}
}
}
int main()
{
char *txt = "Geeks For Geeks";
char *pat = "Geek";
int q = 101; //A prime number
search(pat, txt, q);
getchar();
return 0;
}