周期串

问题来源:《算法竞赛入门经典》

                  如何判断一个字符串是否为某个字符串重复出现所组成:例如 abcabc即为abc重复,abcdabc不是重复子串。

对于这个问题其实就是KMP算法的直接应用。对于KMP的具体含义要有深刻的理解尤其是前缀。

对此个人该觉清华严蔚敏那本书中的KMP算法实现方式比较好理解。KMP算法我们有优化与不优化两种,对此的区别:没有优化的方式,体现的是前缀的关系,而优化过的则不存在这种关系。所以在此我们采用没有优化过的方式。

为什么KMP算法可以实现呢?

例如:abcabcabc其next数组为0 1 1 1 2 3 4 5 6,则以最后cj结尾的字串的前缀为abcabcabc(红色标记),由于是前缀所以从最后一个c往前6个字符(abcabc)与红色(abcabc)部分应该是完全相同的

                    序号 1 2 3 4 5 6 7 8 9

                    next  0 1 1 1 2 3 4 5 6

                             a b c a b c

                                      a b c a b c

       从上我们可以看出循环串的长度为9-next[9],如果你已经知道这个串是循环串那么我们可以知道我们的循环子串为从末尾开始9-next[9]个字符串。如果我们要判断一个串是否为循环子串那么该怎么办呢?

结论:串长为i,如果i%(i-next[i])为0(next[i]不为0,如果为0,那么重复串是整个串。例如abc其重复子串为abc,重复次数为i/(i-next[i]) = 1),那么我们认为该串为重复串重复次数为i/(i-next[i]).对于上述例子:9%(9-next[9]) ==0, 9/(9-next[9]) == 3,所以该串是循环串,循环次数为3,循环串为abc。对于原因大家自己分析下很简单。

void get_next1(int *next, int len, char *pattern)
{
        int j = -1;
        int i = 0;
        while(i < len)
        {
                if(j == -1 || pattern[i] == pattern[j])
                {
                        i++;
                        j++;
                        if(pattern[i] == pattern[j])
                                next[i] = next[j];
                        else
                                next[i] = j;
                                
                                
                }
                else
                        j = next[j];
         }
}

void get_next2(int *next, int len, char *pattern)
{
        int j = 0;
        int i = 1;
        while(i < len)
        {
                if(j == 0 || pattern[i]==pattern[j])
                {
                        i++;
                        j++;
                        next[i] = j;
                }
                
                else
                        j = next[j];
         }
}


上面我们给出了获取next数组的两种方法,第一种为优化过的,第二种是没有忧化的。我们采用第二种方法。

        

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值