KMP与最小覆盖子串

最小覆盖子串:对于某个字符串s,它的最小覆盖子串指的是长度最小的子串p,p满足通过自身的多次连接得到q,最后能够使s成为q的子串。

比如:

对于s="abcab",它的最小覆盖子串p="abc",因为p通过在它后面再接上一个p(即重叠0个字符),可以得到q="abcabc",此时s是q的子串。

对于s="ababab",它的最小覆盖子串为p="ab"。

根据KMP算法的next数组的定义,设字符串s的长度为n,则next[n] = next[n - 1],n-1为s的最后一位。

next[n]表明s[0,1,2,...,next[n]-1] == s[n-next[n],...,n-1],设这两段分别为s1和s2。

若s1和s2的长度之和小于s的长度,则说明s1和s2分别为不重叠的前缀和后缀,则最小覆盖子串必为s截去s2之后得到的前缀。

若s1和s2的长度之和大于等于s的长度,则最小覆盖子串也必为s截去s2之后得到的前缀。

以上两种情况都可以推出这个结论:最小覆盖子串是s的前缀,它的长度为n-next[n]。

我对KMP的一些理解(lyp点拨的):pre[i](或next[i])的实质是串str[1..i]的最长且小于i的“相等前、后缀”分别为str[1..pre[i]](前缀)与str[(i-pre[i]+1)..i](后缀),通俗讲就是:使str[1..i]前k个字母与后k个字母相等的最大k值。

KMP算法详解可见:http://blog.csdn.net/fjsd155/article/details/6864233

另外一个结论:

最小覆盖子串(串尾多一小段时,用前缀覆盖)长度为n-next[n](n-pre[n]),n为串长。

证明分两部分:

1-长为n-next[n]的前缀必为覆盖子串。

当next[n]<n-next[n]时,如图a,长为next[n]的前缀A与长为next[n]的后缀B相等,故长为n-next[n]的前缀C必覆盖后缀B;

当next[n]>n-next[n]时,如图b,将原串X向后移n-next[n]个单位得到Y串,根据next的定义,知长为next[n]的后缀串A与长为前缀串B相等,X串中的长为n-next[n]的前缀C与Y串中的前缀D相等,而X串中的串E又与Y串中的D相等……可见X串中的长为n-next[n]的前缀C可覆盖全串。

2-长为n-next[n]的前缀是最短的。

如图c,串A是长为n-next[n]的前缀,串B是长为next[n]的后缀,假设存在长度小于n-next[n]的前缀C能覆盖全串,则将原串X截去前面一段C,得到新串Y,则Y必与原串长度大于next[n]的前缀相等,与next数组的定义(使str[1..i]前k个字母与后k个字母相等的最大k值。)矛盾。得证!有人问,为什么Y与原串长大于next[n]的前缀相等?由假设知原串的构成必为CCC……E(E为C的前缀),串Y的构成必为CC……E(比原串少一个C),懂了吧!

最后得出结论:总长度-next[n].

code:

// Memory   Time
// 1347K 0MS
// by : Snarl_jsb
// 2014-10-02-21.08
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<climits>
#include<cmath>
#define N 1000010
#define LL long long
using namespace std; string str;
vector<int> next;
void GetNext()
{
int len=str.size();
next.push_back();
int k=;
for(int i=;i<len;++i)
{
if(k!=&&str[i]!=str[k])
k=next[k-];
if(str[i]==str[k])
k++;
next.push_back(k);
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie();
// freopen("C:\\Users\\ASUS\\Desktop\\cin.cpp","r",stdin);
// freopen("C:\\Users\\ASUS\\Desktop\\cout.cpp","w",stdout);
while(cin>>str)
{
next.clear();
int len=str.size();
GetNext();
// for(int i=0;i<len;++i)
// {
// cout<<len-next[i]<<endl;
// }
cout<<"最小覆盖子串为:"<<len-next[len-]<<endl;
}
return ;
}

KMP算法 - 求最小覆盖子串的更多相关文章

  1. POJ 2185 Milking Grid (KMP,求最小覆盖子矩阵,好题)

    题意:给出一个大矩阵,求最小覆盖矩阵,大矩阵可由这个小矩阵拼成.(就如同拼磁砖,允许最后有残缺) 正确解法的参考链接:http://poj.org/showmessage?message_id=153 ...

  2. POJ 3450 Corporate Identity (KMP,求公共子串,方法很妙)

    http://blog.sina.com.cn/s/blog_74e20d8901010pwp.html我采用的是方法三. 注意:当长度相同时,取字典序最小的. #include <iostre ...

  3. KMP算法字符串查找子串

    题目: 经典的KMP算法 分析: 和KMP算法对应的是BF算法,其中BF算法时间复杂度,最坏情况下可以达到O(n*m),而KMP算法的时间复杂度是O(n + m),所以,KMP算法效率高很多. 但是K ...

  4. HDU-3746 Cyclic Nacklace 字符串匹配 KMP算法 求最小循环节

    题目链接:https://cn.vjudge.net/problem/HDU-3746 题意 给一串珠子,我们可以在珠子的最右端或最左端加一些珠子 问做一条包含循环珠子的项链,最少还需要多少珠子 思路 ...

  5. poj3020 Antenna Placement 匈牙利算法求最小覆盖=最大匹配数(自身对应自身情况下要对半) 小圈圈圈点

    /** 题目:poj3020 Antenna Placement 链接:http://poj.org/problem?id=3020 题意: 给一个由'*'或者'o'组成的n*m大小的图,你可以用一个 ...

  6. POJ-2752 Seek the Name, Seek the Fame 字符串问题 KMP算法 求前后缀串相同数木

    题目链接:https://cn.vjudge.net/problem/POJ-2752 题意 给一个字符串,求前缀串跟后缀串相同的前缀串的个数 例:alala 输出:a, ala, alala 思路 ...

  7. HDU-1358 Period 字符串问题 KMP算法 求最小循环节

    题目链接:https://cn.vjudge.net/problem/HDU-1358 题意 给一个字符串,对下标大于2的元素,问有几个最小循环节 思路 对每个元素求一下minloop,模一下就好 提 ...

  8. kmp算法,求重复字符串

    public class Demo { public static void main(String[] args) { String s1 = "ADBCFHABESCACDABCDABC ...

  9. hdoj 3336 Count the string【kmp算法求前缀在原字符串中出现总次数】

    Count the string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

随机推荐

  1. BZOJ 2648: SJY摆棋子 kdtree

    2648: SJY摆棋子 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=2648 Description 这天,SJY显得无聊.在家自己玩 ...

  2. Linux查看端口、进程情况及kill进程

    看端口: ps -aux | grep tomcat 发现并没有8080端口的Tomcat进程. 使用命令:netstat –apn 查看所有的进程和端口使用情况.发现下面的进程列表,其中最后一栏是P ...

  3. wordpress自动截取文章摘要代码

    想要实现 wordpress 首页显示摘要有几种方法: 第一种,可以在写文章的时侯在需要分割的地方加入<!–more–>标签,但在输出首页摘要的同时,也会使feed只显示摘要,不方便读者阅 ...

  4. IOS , plist 配置项说明

    本文转载至 http://blog.csdn.net/fengsh998/article/details/8307424 Key:Application can be killed immediate ...

  5. [原创]自定义view之:快速开发一款Material Design风格的dialog的开源项目MDDialog

    随着google开始主导Material Design风格的设计,越来越多的app开始使用Material Design风格来设计自己的UI.虽然在Android Studio中集成了多种快速开发框架 ...

  6. Spark 实时计算整合案例

    1.概述 最近有同学问道,除了使用 Storm 充当实时计算的模型外,还有木有其他的方式来实现实时计算的业务.了解到,在使用 Storm 时,需要编写基于编程语言的代码.比如,要实现一个流水指标的统计 ...

  7. android 开发 - 网络图片加载库 Fresco 的使用。

    概述 Fresco 是 facebook 的开源类库,它支持更有效的加载网络图片以及资源图片.它自带三级缓存功能,让图片显示更高效. 介绍 Fresco 是一个强大的图片加载组件. Fresco 中设 ...

  8. WinForm 批量设置指定控件中的控件状态

    在开发中常遇到当点击某个按钮的时候,禁用文本框或按钮的的状态,以防止误操作,下面的代码是我已批量设置指定控件中的按钮状态的代码,同理可以延伸出很多操作. /// <summary> /// ...

  9. lxde桌面默认快捷键

    ctrl+alt+左右      选择左右桌面shift+alt+左右     当前窗口送至左右桌面房子键+F1~F4       切换桌面1-4房子键+d           显示桌面alt+esc ...

  10. shell来start、stop、restart应用程序模板

    这里使用shell中的case语法: case分支语句格式如下: case $变量名 in 模式1) 命令列表 ;; 模式2) 命令列表 ;; *) ;; esac case行尾必须为单词“in”,每 ...