Leetcode 459. Repeated Substring Pattern

题目:

Given a non-empty string check if it can be constructed by taking a substring of it and appending multiple copies of the substring together. You may assume the given string consists of lowercase English letters only and its length will not exceed 10000.

思路:

为了将时间复杂度降为O(n),我们这里先学习KMP算法!

KMP算法一般用于模式匹配,即从字符串S中找出子串P对应的位置。


根据KMP算法,在该失配位会调用该位的next数组的值。next数组用于返回主串失配位在下次匹配中应该和P中哪个索引对应的元素进行匹配!

而这个索引值,就是在上图蓝色部分中,存在的最长公共前后缀的长度,如下图绿色部分所示。


所以,接下来失配位会与下图蓝色部分的第一位匹配。


这就是next数组的作用。返回当前的最长公共前后缀长度,假设为len。因为数组是由0开始的,所以next数组让第len位与主串匹配就是拿最长前缀之后的第1位与失配位重新匹配,避免匹配串从头开始。

接下来就是next数组的求解。从第0位开始依次向后计算。

a 、第0位设置为-1,此处的作用是,如果遇到-1,表明此字符与子串的第一个字符都不匹配,此时需要向后进一格与子串第一位重新匹配!第一位一定是0,因为第一位之前只有一个元素,不可能存在对称的前后缀。

b 、然后开始向后计算,如果第i位的值与第i位对应的next[i]索引处的值相等,说明对称前后缀的长度变长了一个单位,所以第i+1位处的next值要加1!举个例子,比如agctag ,倒数第二个 a 的 next 是0 ,说明它前面对称的前后缀长度是0,然后将两个a一比较发现相等,所以最后那个g对应的next是1,因为g之前的对称前后缀长度是1(只有a)接着我们就把最后一个 g 与第二个 g 比较,又相等,自然对称程度就累加了,那g后面的元素对应的next值就是 2 了!

如果蓝色的部分相同,则当前 next 数组的值为上一个 next 的值加一,如果不相同,就是我们下面要说的!


如果遇到下一个不相等了,那么说明不能继承前面的对称性了,这种情况只能说明没有那么多对称了,但是不能说明一点对称性都没有,而是要从前面来找子前后缀

1 、如果要存在对称性,那么对称程度肯定比前面这个的对称程度小,所以要找个更小的对称。

2 、要找更小的对称,必然在对称内部还存在子对称,而且这个必须紧接着在子对称之后。

如果看不懂,那么看一下图吧!

其实就是找下图中最左边的绿色块与最右边的绿色块!


图片来源:http://blog.csdn.net/u0011564456


然后将此算法应用在本题中,给出一个字符串abcabcabc则此串对应的next数组为[-1,0,0,0,1,2,3,4,5]。本题中我们需要对next数组末尾多设置一位,则上面的字符串对应的数组为[-1,0,0,0,1,2,3,4,5,6]。可见如果字符串由重复子串构成,则最后一位一定可以整除那个循环字串的长度(长度为字符串长度减去next数组最后一位);如果字符串不是由重复字串构成,比如abcabcabc,则对应的next数组为[-1,0,0,0,1,2,3,4,5,0]。所以只要next最后一位是0,则表示此字符串一定不满足题目条件!

代码:

C++实现

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int l = s.size();
        int next[l + 1];
        next[0] = -1;
        int j = 0;
        int k = -1;
        while(j < l){
            if (k == -1 || s[j] == s[k]){
                j++;
                k++;
                next[j] = k;
            }
            else{
                k = next[k];
            }
        }
        return next[l] && l%(l - next[l]) == 0;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值