重复的子字符串

给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。

1. 暴力匹配

列举不同子串长度,比较字符串

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int n = s.size();
        for(int i=1;i<=n/2;i++){//当前分割长度
            if(n%i!=0) continue;
            string base = s.substr(0,i);
            bool flag = true;
            for(int index=i;index<n;index=index+i){
                if(s.substr(index,i)!=base){flag = false; break;}
            }
            if(flag) return true;
        }
        return false;
    }
};

列举长度,与前面进行逐个字符比较

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int n = s.size();
        for(int i=1;i<=n/2;i++){//当前分割长度
            if(n%i!=0) continue;
            bool flag = true;
            for(int index=i;index<n;index++){
                if(s[index]!=s[index-i]){flag = false; break;}
            }
            if(flag) return true;
        }
        return false;
    }
};

2. 正则表达式

regex re("(.+)\\1+"); //C++
class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        return regex_match(s,re);
    }
};

3. 技巧(数学证明)

循环字符串往左移位n次与原字符串匹配,这里用两个字符串叠加,然后去掉首尾,在其中找原字符串

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        return (s + s).find(s, 1) != s.size();
    }
};

4. KMP算法

class Solution {
public:
    bool kmp(const string& pattern) {
        int n = pattern.size();
        vector<int> fail(n, -1);
        for (int i = 1; i < n; ++i) {
            int j = fail[i - 1];
            while (j != -1 && pattern[j + 1] != pattern[i]) 
                j = fail[j];
            if (pattern[j + 1] == pattern[i]) 
                fail[i] = j + 1;
        }
        //上面已经计算出了每个位置的上一个相同值位置
        //如果串由周期串构成,则两位置差就是周期串的长度,应该满足串长度是周期串长度整数倍
        return fail[n - 1] != -1 && n % (n-1 - fail[n - 1]) == 0;
    }

    bool repeatedSubstringPattern(string s) {
        return kmp(s);
    }
};

posted @ 2023-08-04 00:13  失控D大白兔  阅读(11)  评论(0编辑  收藏  举报