先给出公式 ans = n - LPS[n-1]

其中ans为最小周期,n为给出的由假设的周期字符串中提取出的子串长度,LPS为前缀函数,n-1为字符串最后的位置下标

证明如下

证明ans = n - LPS[n-1],思路:

(1) 证明特殊情况,即先对完整周期字符串进行证明,这时候的字符串组成是 [1][2][3][4] ,即4个周期拼接,所以由前缀函数的定义,有

 [1][2][3] = [2][3][4],所以LPS[n-1] = 3*T,即三个周期,则ans = n(即4*T) - LPS[n-1] = 4*T - 3*T = T;

 对于完整周期子串显然成立.

(2) 证明一般情况,即证明非完整周期字符串,假设给出的字符串是 [末部分][1][2][3][前部分] ,即中间有完整的周期,两边是不确定长度的,可能为0.

(为了方便,此处取[末部分] = [e],[前部分] = [b])

 1,当len([e]) = len([b]) = 0时,即(1)的情况,显然成立.

 2,当len([e]) = 0,len([b]) != 0时此时字符串为 [1][2][3][b],由于[b]是周期的一部分,则[3]中包含[b],有
[1][2][b] = [2][3][b],此时 LPS[n-1] = 2*T + len([b]), n = 3*T + len([b]),显然有
ans = n - LPS[n-1] == 3*T + len([b]) - 2*T - len([b]) = T,成立. 3,当len([b]) = 0,len([e]) != 0时同理. 4,当len([e]) != 0,且len([b]) != 0时,此时字符串为 [e][1][2][3][b],根据2,3,有
[e][1][2][b] = [e][2][3][b],符合前缀函数定义,此时LPS[n-1] = 2*T + len([b+e]),n = 3*T + len([b+e])
显然有ans = n - LPS[n-1] = T,得证 5,当[e][b]内部没有完整的周期时,显然[e][b]可以自己组成最小周期,此时的LPS[n-1] = 0,ans = len([e+b]),为自己,得证

附上例题加以理解:

1,KMP算法模板https://www.luogu.com.cn/problem/P3375

2,字符串周期模板题https://www.luogu.com.cn/problem/P4391

例题1代码解析:

点击查看代码
//背景:刚学LPS函数及其应用KMP,先来道模板题练习,结果发现细节多
//注意:以后我的所有关于KMP的算法的字符串下标均是从0开始(便于与OI-wiki统一,好记忆)
//原理:KMP匹配字符串
//时间复杂度:o(n+m)
#include <bits/stdc++.h>
using namespace std;
void Prefixion(int LPS[],string s)//求生成字符串的前缀函数
{
LPS[0] = 0;//初始化前缀
for (int i = 1,big = s.size();i<big;i++)//遍历字符串
{
int j = LPS[i-1];//获取上一个位置的LPS
while(j>0&&s[j] != s[i]) j = LPS[j-1];//寻找第一个使得当前位置i的前缀性质仍满足的j
if(s[j] == s[i]) j++;//如果是因为相等退出循环的,j是位置,那么长度为j+1
LPS[i] = j;//记录当前位置的LPS
}
}
void KMP()//KMP算法
{
string text,pattern;
cin>>text>>pattern;//输入文本字符串及模板字符串(待查找的字符串)
string cur = pattern + '#' + text;//生成新的字符串
int s1 = pattern.size();//计算模板字符串的长度
int s2 = text.size();//计算文本字符串的长度
int LPS[s2+s1+1];//注意这里LPS的数组大小,如果开小了退不出函数(我也不知道为什么)
Prefixion(LPS,cur);//求生成字符串的前缀函数
vector<int> occurrence;//记录文本字符串匹配成功的起始位置
for (int i = s1+1;i<=s2+s1;i++)//从生成字符串的文本位置开始遍历
{
if(LPS[i] == s1) occurrence.push_back(i-2*s1);//如果满足当前情况,即记录下成功匹配的位置(相对文本):当前位置 - 2*模板长度
}
for (auto v:occurrence) cout<<v+1<<"\n";//依次输出位置(相对文本的)
for (int i = 0;i<s1;i++) cout<<LPS[i]<<" ";//输出每个前缀的函数值
cout<<"\n";
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t = 1;
while(t--)
{
KMP();
}
return 0;
}

例题2代码解析:

点击查看代码
//背景:字符串的周期性问题,一开始不太理解,后来看了题解自己画图推导出来了
//本题题意:本题给出的是重复拼接字符串子串,求最小周期,也就是说假定了原字符串是周期函数,给分析证明提供了思路
//公式:ans = n - LPS[n-1]
#include <bits/stdc++.h>
using namespace std;
void Prefixion(int LPS[],string s)//前缀函数
{
LPS[0] = 0;//不要忘了初始化
for (int i = 1;s[i] != '\0';i++)
{
int j = LPS[i-1];
while(j > 0&&s[j] != s[i]) j = LPS[j-1];
if(s[j] == s[i]) j++;
LPS[i] = j;
}
}
void Solve()
{
int n;
string s;
cin>>n;//输入子串长度
cin>>s;//输入字符串
int LPS[n];//定义前缀函数
Prefixion(LPS,s);//求前缀函数
cout<<n - LPS[n-1]<<"\n";//输出最小周期
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t = 1;
while(t--)
{
Solve();
}
return 0;
} /*证明ans = n - LPS[n-1],思路:
(1)证明特殊情况,即先对完整周期字符串进行证明,这时候的字符串组成是 [1][2][3][4] ,即4个周期拼接,所以由前缀函数的定义,有 [1][2][3] = [2][3][4],所以LPS[n-1] = 3*T,即三个周期,则ans = n(即4*T) - LPS[n-1] = 4*T - 3*T = T; 对于完整周期子串显然成立. (2)证明一般情况,即证明非完整周期字符串,假设给出的字符串是 [末部分][1][2][3][前部分] ,即中间有完整的周期,两边是不确定长度的,可能为0. (为了方便,此处取[末部分] = [e],[前部分] = [b]) 1,当len([e]) = len([b]) = 0时,即(1)的情况,显然成立. 2,当len([e]) = 0,len([b]) != 0时此时字符串为 [1][2][3][b],由于[b]是周期的一部分,则[3]中包含[b],有
[1][2][b] = [2][3][b],此时 LPS[n-1] = 2*T + len([b]), n = 3*T + len([b]),显然有
ans = n - LPS[n-1] == 3*T + len([b]) - 2*T - len([b]) = T,成立. 3,当len([b]) = 0,len([e]) != 0时同理. 4,当len([e]) != 0,且len([b]) != 0时,此时字符串为 [e][1][2][3][b],根据2,3,有
[e][1][2][b] = [e][2][3][b],符合前缀函数定义,此时LPS[n-1] = 2*T + len([b+e]),n = 3*T + len([b+e])
显然有ans = n - LPS[n-1] = T,得证 5,当[e][b]内部没有完整的周期时,显然[e][b]可以自己组成最小周期,此时的LPS[n-1] = 0,ans = len([e+b]),为自己,得证

码字不易,多多支持!

KPM算法求字符串的最小周期证明的更多相关文章

  1. UVA.455 Periodic Strings(字符串的最小周期)

    Periodic Strings 模板 题意分析 判断字符串的最小周期 代码总览 /* Title:UVA.455 Author:pengwill Date:2016-12-16 */ #includ ...

  2. kmp的next数组的运用(求字符串的最小循环节)

    hdu3746 Cyclic Nacklace Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/ ...

  3. Uvalive - 3026 Period (kmp求字符串的最小循环节+最大重复次数)

    参考:http://www.cnblogs.com/jackge/archive/2013/01/05/2846006.html 总结一下,如果对于next数组中的 i, 符合 i % ( i - n ...

  4. POJ--2406Power Strings+KMP求字符串最小周期

    题目链接:点击进入 事实上就是KMP算法next数组的简单应用.假设我们设这个字符串的最小周期为x 长度为len,那么由next数组的意义,我们知道len-next[len]的值就会等于x.这就是这个 ...

  5. E - Power Strings,求最小周期串

    E - Power Strings Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u S ...

  6. ipv4 ipv6 求字符串和整数一一映射的算法 AmazonOrderId

    字符串和整数一一映射的算法 公司每人的英文名不同,现在给每个英文名一个不同的数字编号,怎么设计? 走ipv4/6  2/32 2/128就够了,把“网段”概念对应到“表或库”,ip有a_e5类,这概念 ...

  7. hdu 4333"Revolving Digits"(KMP求字符串最小循环节+拓展KMP)

    传送门 题意: 此题意很好理解,便不在此赘述: 题解: 解题思路:KMP求字符串最小循环节+拓展KMP ①首先,根据KMP求字符串最小循环节的算法求出字符串s的最小循环节的长度,记为 k: ②根据拓展 ...

  8. 【KMP求最小周期】POJ2406-Power Strings

    [题意] 给出一个字符串,求出最小周期. [思路] 对KMP的next数组的理解与运用orz ①证明:如果最小周期不等于它本身,则前缀和后缀必定有交叉. 如果没有交叉,以当前的next[n]为最小周期 ...

  9. sw算法求最小割学习

    http://  blog.sina.com.cn/s/blog_700906660100v7vb.html 转载:http://www.cnblogs.com/ylfdrib/archive/201 ...

  10. poj 3565 uva 1411 Ants KM算法求最小权

    由于涉及到实数,一定,一定不能直接等于,一定,一定加一个误差<0.00001,坑死了…… 有两种事物,不难想到用二分图.这里涉及到一个有趣的问题,这个二分图的完美匹配的最小权值和就是答案.为啥呢 ...

随机推荐

  1. CS101

    Turing machine:图灵机 理论上可以计算任何东西 CPU(Center Process Unit):中央处理器 是现代电脑的"大脑",其中包含数十亿细小开关的硅片,即晶 ...

  2. 美丽的夕阳qsnctfwp

    题目附件 查看图片,放大左侧发现建筑物上 8 个字:龙腾公寓/福阳集团 根据文字在搜索引擎中查找,并由此确定城市 通过百度地图全景地图查看当地桥梁,并与照片比对 调整地图比例尺,记录桥名 根据提示qs ...

  3. Python 爬虫进阶五之多线程的用法

    Python 爬虫进阶五之多线程的用法 作者 崔庆才   发表于 2016-11-03   分类于 Python   阅读次数: 60553   本文字数: 7.5k   阅读时长 ≈ 7 分钟 前言 ...

  4. CentOS 5.5编译安装vsftpd-2.3.4配置虚拟用户

    CentOS 5.5编译安装vsftpd-2.3.4配置虚拟用户 2012-02-22 17:18:15|  分类: rhel_vsftp|举报|字号 订阅 centos 5.5编译安装vsftpd- ...

  5. Xilinx USB JTAG两种JTGA-HS3和Platfrom下载器速度对比

    下面测试速度,以一个V7的配置文件为例子.文件大小如下,27MB.特别是对于有点规模的项目配置文件都是很大的.总不能是点灯项目. 选择普通的下载器,Platform Cable USB.这种下载器是基 ...

  6. 【cef编译包】下载地址

    http://opensource.spotify.com/cefbuilds/index.html

  7. 第五課-Channel Study TCP Listener & Web Service Listener

    示例描述: 我们将研究如何获取相当常见的HL7 v2消息并将其映射到自定义Web Service接口服务.在许多实际情况下,当我们要连接到HIE,EMPI,数据仓库或数据存储库时,必须这样做.此用例说 ...

  8. 力扣182(java&python)-数组元素积的符号(简单)

    题目: 已知函数 signFunc(x) 将会根据 x 的正负返回特定值: 如果 x 是正数,返回 1 .如果 x 是负数,返回 -1 .如果 x 是等于 0 ,返回 0 .给你一个整数数组 nums ...

  9. 力扣119(java)-杨辉三角Ⅱ(简单)

    题目: 给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行. 在「杨辉三角」中,每个数是它左上方和右上方的数的和. 示例 1: 输入: rowIndex = 3输出: [1 ...

  10. 【ModelScope】5分钟让你在大火的多模态领域权威榜单VQA上超越人类

    简介: ModelScope上开源了达摩院众多业界最强多模态模型,其中就有首超人类的多模态视觉问答模型mPLUG,小编从页面体验(一探).开发体验(二探).开放测试(三探)来探究多模态预训练模型能力. ...