給定一個非空的字符串,判斷它是否可以由它的一個子串重複多次構成。給定的字符串只含有小寫英文字母,並且長度不超過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;
}