leetcode 459. Repeated Substring Pattern kmp算法运用

0 题意:求一个字符串是否可能由其子串复制而成

1 分析,假如一个串s由子串x复制而成,那么设子串为x = (abc...),则 s = x x x x x...。我们可以对其使用kmp算法,求出前缀、后缀字符串的最大长度,然后进行问题简化。

2 图解,假如串s在用kmp求解后,串尾的最长前缀后缀长度为k,那么前面x长度为多余的部分,如②的串b的前面x部分;那么s[0,x]与s[0,k]有何关系呢?下面证明串s为x进行多次拷贝的串,是 k%x == 0 的重要条件。

3 证明,充分性:当串s为x进行多次拷贝时,假设为m次,则可得出k = (m-1)*x,则有k%x==0成立。必要性:x为串s的起始子串,由于串a ==b (a和b是分别通过前缀串,后缀串抽象出来的),所以a[0,x] == b[0,x] 。由于k%x ==0,由kmp导致的前缀串与后缀串的性质可知,a[0,x] == b[x, 2*x] 。依次往后递归,可知a[n-x*2, n-x] == b[n-x, n]。再由于a ==b,所以, b[n-x,n] == a[n-x,n] ,综上串s是串x的k+1次拷贝。

4 总结 最后,我们可以得到整个题目的解决思路:首先用kmp对串s求table,然后得到串末尾的最大后缀串长度k;首先判断k不为0,如果是0的话,那么最后一个字符无法得到匹配,那么整个串都将无法匹配。其次判断x = n-k是否被k整除,如果整除的话,再利用第三点证明的必要性,则可以进行说明串s是串x的k+1个拷贝。

5 代码

bool repeatedSubstringPattern(string s)
{
    int n = s.size();
    if (n <= 1)
        return false;
    vector<int> table(n, 0);
    for (int i = 1; i < n; ++i)
    {
        int k = table[i - 1];
        while (k != 0 && s[k] != s[i])
            k = table[k - 1];
        table[i] = k + (s[k] == s[i]);
    }
    //for(auto i:table) cout<<i<<" ";
    //cout<<endl;
    return (table[n - 1] != 0 && table[n - 1] % (n - table[n - 1]) == 0);
}

猜你喜欢

转载自blog.csdn.net/mistakk/article/details/83180658