空でない文字列が与えられた場合、それが複数回繰り返される部分文字列で構成できるかどうかを判断します。指定された文字列には小文字の英字のみが含まれ、長さは10,000を超えません。
例1:
入力:「abab」
出力:True
説明:部分文字列「ab」は2回繰り返すことができます。
例2:
入力:「aba」
出力:False
例3:
入力:「abcabcabcabc」
出力:True
説明:部分文字列「abc」は4回繰り返すことができます。(または、部分文字列「abcabc」が2回繰り返されます。)
分析:主にこのトピックを使用して、次の配列の構築方法を習得し、最初にnext [0]の値を設定し(この値は次の配列の全体的な表現も決定します)、i、jの位置を初期化し、位置がiの文字列。各トラバーサルはs [i]とs [j]の等式関係を比較します(jの位置が後退するのを待ちたくありません。1つの後退とは、同じプレフィックスの値とiの位置の接尾辞も削減されます。同様に、等しい場合はjが追加されます。1)各ループの最後に、jの現在の位置に応じて、等しい連続文字(文字列)がいくつ表されますか。 、next [i] = j。次の配列では、メモリストレージと同等です。doubleforループで単語を検索する文字列の外側のループでトラバーサルをスキップして、無駄なトラバーサルを減らすことができます。コードは次のとおりです。 :
class Solution {
public:
void getNext(int* next, const string& s){
next[0] = -1;
int j = -1;
for (int i = 1; i < s.size(); i++){
// 准备j回退的
while(j >= 0 && s[i] != s[j+1]){
j = next[j];
}
// 向右前进
if(s[i] == s[j + 1]){
j++;
}
next[i] = j;
}
// for (int i = 0; i < s.size(); i++) cout << next[i] << " ";
}
bool repeatedSubstringPattern(string s) {
if (s.size() == 0) return false;
int next[s.size()];
getNext(next, s);
int len = s.size();
// next[len - 1] + 1 = 3 + 1 = 4,最长公共前后缀的长度
// 以ababab为例,4就是abab这个公共部分
if (next[len - 1] != -1 && len % (len - (next[len - 1] + 1)) == 0) {
return true;
}
return false;
}
};