KMP求字符串循环节

 

知识支持:

  [1]:KMP学习资料:左神进阶班第一节   [ 提取码:3knt ]

 

本节内容主要谈谈我对KMP求字符串循环节的理解:

  利用KMP算法中的 next 数组可以求出字符串的循环次数,间接就可以求出循环节的内容和循环节长度。

  结论:长度为 len 的字符串, 如果 (len - next[len]) | len ,则循环次数为 len / (len - next[len]),否则为1。

  (字符串下标从 0 开始)

 

  分三种情况讨论

  

  情况①:显然  len-next[len] | len , 循环次数为 2

  情况②:len-next[len] 一定不整除 len,证明如下:

    假设 s串 由若干个 a 串和 b 串组成,为方便表述,就固定有4个a串和1个b串,且假设|a| = a , |b| = b:

        

    假设 len-next[len] | len , 即 2a+b | 4a+b;
    由带余除法可得 b = ka+r; ( 0 <= r < a)
    那么 2a+b | 4a+b ⇔ (2+k)a+r | (4+k)a+r;
    相当于 [(4+k)a+r] % [(2+k)a+r] = 0;
    下面我们来化简这个式子:
    [(4+k)a+r] % [(2+k)a+r] = [(2+k)a+r+2a] % [(2+k)a+r] = 2a%[(2+k)a+r];
    易得 (2+k)a+r > 2a;(k和r不会同时为0,除非 b = 0,这就与题设不符了)
    所以 2a % [(2+k)a+r] = 2a ≠0;
    所以假设不成立;
    证毕;

  情况③:(证明待给出)

    (3.1)假设 s串 由长度为 a 的串循环 k 次构成:

    

    len = k*a , next[ len ] = (k-1)*a;

    len - next[len] = a , len / (len - next[len] = k;

    所以可得循环次数为 k;

    (3.2)

    ..........................


 

 KMP求字符串循环节的应用:

  给出一字符串 s,求出最少需要增加多少字符使得字符串 s 变成循环次数 ≥ 2 的串?

  1.如果 len%(len-nex[len]) == 0 && nex[len] != 0 ,答案为 0;

  2.如果 2*next[len] < len,答案为 len-2*nex[len];

  3.如果 2*next[len] ≥ len,设 k = len-next[len],那么答案为 k-len%k;

 

  我的理解:(ps:图片中出现的字母全为相应子串的长度)

  情况1显而易见;

  情况2对应的字符串如下图所示:

  

  字符串s的最长公共前缀与最长公共后缀不重合,那么最少需要增加 b 个字符,形成 abab 类型的循环串;

  b = len - 2*next[len];

  情况3对应的字符串如下图所示:

  

  字符串s的最长公共前缀与最长公共后缀重合,重合长度为 b,那么只需在 x 后补充字符 s[ x,x+1,...,a-1 ] 便可构成循环节为

  s[ 0,.....,a-1 ] 的循环串,此时最少需要增加 a-x 个字符;

  b = 2*next[len] - len;

  a = next[len]-b = len-next[len];

  x = len%a;

  a-x = a-len%a;

 

转载于:https://www.cnblogs.com/violet-acmer/articles/10480077.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值