KMP求字符串循环节

本文探讨了如何使用KMP算法求解字符串的循环节,详细解析了三种情况下的循环次数判断,并提供了求解最少字符增加以形成循环串的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

知识支持:

  [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

KMP算法的核心在于构建部分匹配表(也称为`next`数组),该表用于记录模式串的部分匹配信息。通过这些信息,可以在寻找重复子串的过程中优化查找效率。 要利用KMP算法来找出字符串的最小循环节,可以通过以下方法实现: ### 使用 KMP 找到最小循环节 对于一个长度为 `n` 的字符串 `s`,如果存在某个最小子串 `p` 能够通过多次复制构成原字符串,则这个子串即是最小循环节。以下是具体过程: #### 构建 Next 数组 定义一个辅助函数计算前缀函数值并存储于 next 数组中。此操作的时间复杂度为 O(n)[^1]。 ```python def compute_next_array(pattern): n = len(pattern) next_arr = [0] * n j = 0 for i in range(1, n): while j > 0 and pattern[i] != pattern[j]: j = next_arr[j - 1] if pattern[i] == pattern[j]: j += 1 next_arr[i] = j return next_arr ``` #### 计算最小循环节 基于上述得到的 next 数组,我们可以进一步推导出最小周期 t=n−next[n−1] 。当满足条件 (t 可整除 n),则表明 s 存在一个大小为 t 的基本单元反复拼接而成;否则整个字符串本身不具备更短的有效循环结构。 ```python def find_smallest_repeating_substring(s): next_arr = compute_next_array(s) length_of_string = len(s) period = length_of_string - next_arr[-1] if length_of_string % period == 0 and period != length_of_string: return s[:period] else: return s ``` 以上代码片段展示了如何应用 KMP 中的 next 数组特性去检测是否存在以及返回目标字符串内的最简重复序列。 ### 结论 综上所述,借助 KMP 算法不仅可以高效解决模式匹配问题,在特定场景下还能巧妙运用于诸如发现字符串内部隐藏规律的任务之中,比如本例中的定位最小循环单位即是如此。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值