KMP算法及应用(hdu2087剪花布条 )Power Strings (POJ2046)Cyclic Nacklace(HDU3746)

本文主要是介绍KMP算法及应用(hdu2087剪花布条 )Power Strings (POJ2046)Cyclic Nacklace(HDU3746),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

KMP由Knuth(D.E.Knuth)、Morris(J.H.Morris)和Pratt(V.R.Pratt)三人设计的线性时间字符串匹配算法。所以叫做KMP。。。。。
字符串匹配,就是从一个字符串中查找出另一个字符串所在位置,当然也可能出现查询不到的情况。

比如给出目标字符串 ss:
  • abcabcabce
所要匹配的模式串 s:
  • abcabce
    这里写图片描述
    当匹配到前6位是,都是成功的,但是到第7位就失败了(ss[6]!=s[6]),我们通长的做法是回溯到ss的第2位,然后让s重新开始从第一位匹配,这样的时间复杂度明显是n*m(n和m分别是ss串和s串的长度),所以就可以想能不能用其他方法解决。

以下是我的理解:

1.我们观察模式串的特点:

前三位abc和第4-6位abc 是相同的,如果说当前6位都是匹配的,把s字符串往后移动三位,是不是前三位也是匹配的。
这里写图片描述
虽然我们知道后面一定是匹配的,但是通常情况下,还是得让计算机跑一遍,(虽然是无用功,但是形式还是要走滴,所以就有TLE……不扯了,扎心qaq)

2.再来看这一个字符串

这里写图片描述
目标串(蓝色)的每一位都不相同,但是依然匹配到第六位失败,注意是每一位都不相同,所以当回溯到下一步的时候,很明显,一定没有一个字符是能匹配成功的,所以又做了无用功
这里写图片描述

3.额,,再看一对串

这里写图片描述
这个很有特点,前面的字符都是一样的,只有最后一个不一样,看到最后一个适配后,肯定知道,应该将模式字符向后移动6位嘛(但是计算机没有人的智商,所以我们需要写一个程序然她,他,它,听话)

为了避免不必要的流程,让时间复杂度降到最低,所以,K,M,P,三人总结出,—->KMP

  • ####KMP是如何工作的
    这里写图片描述
    如果是通常算法的话,需要16步比较,而kmp就只要。。。。

为什么能过省略那么多比较过程呢?———KMP的核心next[]跳转表

其实,模式串往往含有一定的信息——前缀包含。
对于模式串而言,其前缀字符串,有可能也是模式串中的非前缀子串,这个问题我称之为前缀包含问题。
如果不理解上述,,请忽略,看下面的解释
这里写图片描述
如图这个模式字符串,后面三位和前面的三位相同,所以就可以姑且理解为前缀包含。。
以模式串a b c a b c a c a b为例,其前缀的4个字符a b c a,正好也是模式串的一个子串a b c (a b c a) c a b,所以当目标串与模式串执行匹配的过程中,如果直到第 8 个字符才匹配失败,同时也意味着目标串当前字符之前的 4 个字符,与模式串的前 4 个字符是相同的,所以当模式串向后移动的时候,可以直接将模式串的第 5 个字符与当前字符对齐,执行比较,这样就实现了模式串一次性向前跳跃多个字符。
next数组就起到能一次性跳跃多个字符的作用
这里写图片描述
next中下标k含义:对于模式串的第 j 个字符 s[j],是所有满足使 s[1···k-1] =s[j-(k-1)···j-1] (k < j) 成立的 k 的最大值。next[j]=k
简单来说就是当前后缀字符中所包含的前缀的最大值
先不管next怎么用,先来看是怎么得到的:

void getnex(int nex[],char *s)
{int len=strlen(s);int i,j=-1;nex[0]=-1;for(i=1;i<len;i++){while(j>-1&&s[j+1]!=s[i])j=nex[j];if(s[j+1]==s[i])j++;nex[i]=j;}
}
//这里用nex表示next数组,在c++中next已经变成保留字符串,所以不能用next当做跳转数组名,否则报错
还有这种写法
void get_nex(int nex[],char *s)
{int len=strlen(s);int i=0,j=-1;nex[0]=-1;while(i!=len)       {if(j==-1||s[i]==s[j])nex[++i]=++j;else  j=nex[j];}
}
//和上面那种写法区别,建议自己试试
看next是如何完成跳转的
int kmp(char *ss,char *s,int nex[])
{getnex(nex,s);int lens=strlen(s);int lenss=strlen(ss);int i,j=-1;for(i=0;i<lenss;i++){while(j>-1&&s[j+1]!=ss[i])j=nex[j];if(s[j+1]==ss[i])j++;if(j==lens-1){return i-lens+1;//找到模式串,返回在在目标串第一个字符位置}}
}

具体看一个问题
问题(hdu2087剪花布条 )
一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?
Input
输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。
Output
输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。
Sample Input
abcde a3
aaaaaa aa
#
Sample Output
0
3
这个题的思路很明显,就是要找出目标串中的“花纹字符串”,虽然暴力能过,但还举荐用kmp

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<cmath>using namespace std;
void getnex(char *s,int nex[])
{int j=-1;int len=strlen(s);nex[0]=-1;int i;for(i=1;i<len;i++){while(j>-1&&s[j+1]!=s[i])j=nex[j];if(s[j+1]==s[i])j++;nex[i]=j;}
}
int kmp(char *ss,char *s,int nex[])
{getnex(s,nex);int i,j,lenss,lens;lenss=strlen(ss);lens=strlen(s);j=-1;int ans=0;for(i=0;i<lenss;i++){while(j>-1&&s[j+1]!=ss[i])j=nex[j];if(s[j+1]==ss[i])j++;if(j==lens-1){j=-1;ans++;}}return ans;
}
int main()
{char ss[1005],s[1005];while(~scanf("%s",ss)){if(strcmp(ss,"#")==0) break;scanf("%s",s);int nex[1005];int ans=kmp(ss,s,nex);printf("%d\n",ans);}return 0;
}
循环节问题

什么是循环节?
—->baidu

利用KMP算法中的next值可以求出字符串的循环节,如ababab的循环节为ab,abcd的循环节为abcd,具体做法如下:假设字符串的长度为len,next[len]为字符串的最后一个字符的下一个字符的next值(下标从0开始),如果len % (len - next[len]) == 0,那么循环节的循环次数为len / (len - next[len]),否则为1

循环节问题
Power Strings (POJ2046)
Given two strings a and b we define a*b to be their concatenation. For example, if a = “abc” and b = “def” then a*b = “abcdef”. If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = “” (the empty string) and a^(n+1) = a*(a^n).
Input
Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.
Output
For each s you should print the largest n such that s = a^n for some string a.
Sample Input
abcd
aaaa
ababab
.
Sample Output
1
4
3
Hint
This problem has huge input, use scanf instead of cin to avoid time limit exceed.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<cmath>using namespace std;
char s[1000000+100];
int nex[1000000+100];
void get_nex(int nex[],char *s)
{int len=strlen(s);int i=0,j=-1;nex[0]=-1;while(i!=len){if(j==-1||s[i]==s[j])nex[++i]=++j;else  j=nex[j];}
}
int main()
{int T,i;while(scanf("%s",s)){if(strcmp(s,".")==0) break;int len=strlen(s);get_nex(nex,s);int t=len-nex[len];if(len%t==0&&nex[len]!=0)printf("%d\n",len/t);else printf("%d\n",1);}return 0;
}

还有循环节的扩展问题
Cyclic Nacklace(HDU3746)
CC always becomes very depressed at the end of this month, he has checked his credit card yesterday, without any surprise, there are only 99.9 yuan left. he is too distressed and thinking about how to tide over the last days. Being inspired by the entrepreneurial spirit of “HDU CakeMan”, he wants to sell some little things to make money. Of course, this is not an easy task.

As Christmas is around the corner, Boys are busy in choosing christmas presents to send to their girlfriends. It is believed that chain bracelet is a good choice. However, Things are not always so simple, as is known to everyone, girl’s fond of the colorful decoration to make bracelet appears vivid and lively, meanwhile they want to display their mature side as college students. after CC understands the girls demands, he intends to sell the chain bracelet called CharmBracelet. The CharmBracelet is made up with colorful pearls to show girls’ lively, and the most important thing is that it must be connected by a cyclic chain which means the color of pearls are cyclic connected from the left to right. And the cyclic count must be more than one. If you connect the leftmost pearl and the rightmost pearl of such chain, you can make a CharmBracelet. Just like the pictrue below, this CharmBracelet’s cycle is 9 and its cyclic count is 2:

这里写图片描述
Now CC has brought in some ordinary bracelet chains, he wants to buy minimum number of pearls to make CharmBracelets so that he can save more money. but when remaking the bracelet, he can only add color pearls to the left end and right end of the chain, that is to say, adding to the middle is forbidden.
CC is satisfied with his ideas and ask you for help.
Input
The first line of the input is a single integer T ( 0 < T <= 100 ) which means the number of test cases.
Each test case contains only one line describe the original ordinary chain to be remade. Each character in the string stands for one pearl and there are 26 kinds of pearls being described by ‘a’ ~’z’ characters. The length of the string Len: ( 3 <= Len <= 100000 ).
Output
For each case, you are required to output the minimum count of pearls added to make a CharmBracelet.
Sample Input
3
aaa
abca
abcde
Sample Output
0
2
5

*这个题就是要求给出字符串,,问还差几位,能形成循环节
所以,直接上代码*

#include<iostream>
#include<stdio.h>
#include<cstring>
using namespace std;
char a[100001];
int nexts[100001];
int main()
{int T,len,i,j,nima;while(scanf("%d",&T)!=EOF){getchar();while(T--){scanf("%s",a+1);len=strlen(a+1);i=1;j=0;nexts[1]=0;while(i<=len){if(j==0||a[i]==a[j]){i++;j++;nexts[i]=j;}elsej=nexts[j];}nima=(len+1)-nexts[len+1];if(len%nima==0&&len!=nima)//这里要注意个是循环节的长度不能等于它自己本身就是len!=nimaprintf("%d\n",0);elseprintf("%d\n",nima-len%nima);}}return 0;
}
//别在意nima这个变量名

这次kmp先写到这,讲真的真不好理解。。。。。。可能我太菜 了吧

这篇关于KMP算法及应用(hdu2087剪花布条 )Power Strings (POJ2046)Cyclic Nacklace(HDU3746)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/402676

相关文章

Python使用Tkinter打造一个完整的桌面应用

《Python使用Tkinter打造一个完整的桌面应用》在Python生态中,Tkinter就像一把瑞士军刀,它没有花哨的特效,却能快速搭建出实用的图形界面,作为Python自带的标准库,无需安装即可... 目录一、界面搭建:像搭积木一样组合控件二、菜单系统:给应用装上“控制中枢”三、事件驱动:让界面“活”

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

Python Flask 库及应用场景

《PythonFlask库及应用场景》Flask是Python生态中​轻量级且高度灵活的Web开发框架,基于WerkzeugWSGI工具库和Jinja2模板引擎构建,下面给大家介绍PythonFl... 目录一、Flask 库简介二、核心组件与架构三、常用函数与核心操作 ​1. 基础应用搭建​2. 路由与参

Spring Boot中的YML配置列表及应用小结

《SpringBoot中的YML配置列表及应用小结》在SpringBoot中使用YAML进行列表的配置不仅简洁明了,还能提高代码的可读性和可维护性,:本文主要介绍SpringBoot中的YML配... 目录YAML列表的基础语法在Spring Boot中的应用从YAML读取列表列表中的复杂对象其他注意事项总

电脑系统Hosts文件原理和应用分享

《电脑系统Hosts文件原理和应用分享》Hosts是一个没有扩展名的系统文件,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应... Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应

CSS 样式表的四种应用方式及css注释的应用小结

《CSS样式表的四种应用方式及css注释的应用小结》:本文主要介绍了CSS样式表的四种应用方式及css注释的应用小结,本文通过实例代码给大家介绍的非常详细,详细内容请阅读本文,希望能对你有所帮助... 一、外部 css(推荐方式)定义:将 CSS 代码保存为独立的 .css 文件,通过 <link> 标签

Python使用Reflex构建现代Web应用的完全指南

《Python使用Reflex构建现代Web应用的完全指南》这篇文章为大家深入介绍了Reflex框架的设计理念,技术特性,项目结构,核心API,实际开发流程以及与其他框架的对比和部署建议,感兴趣的小伙... 目录什么是 ReFlex?为什么选择 Reflex?安装与环境配置构建你的第一个应用核心概念解析组件

C#通过进程调用外部应用的实现示例

《C#通过进程调用外部应用的实现示例》本文主要介绍了C#通过进程调用外部应用的实现示例,以WINFORM应用程序为例,在C#应用程序中调用PYTHON程序,具有一定的参考价值,感兴趣的可以了解一下... 目录窗口程序类进程信息类 系统设置类 以WINFORM应用程序为例,在C#应用程序中调用python程序

Java应用如何防止恶意文件上传

《Java应用如何防止恶意文件上传》恶意文件上传可能导致服务器被入侵,数据泄露甚至服务瘫痪,因此我们必须采取全面且有效的防范措施来保护Java应用的安全,下面我们就来看看具体的实现方法吧... 目录恶意文件上传的潜在风险常见的恶意文件上传手段防范恶意文件上传的关键策略严格验证文件类型检查文件内容控制文件存储

CSS3 布局样式及其应用举例

《CSS3布局样式及其应用举例》CSS3的布局特性为前端开发者提供了无限可能,无论是Flexbox的一维布局还是Grid的二维布局,它们都能够帮助开发者以更清晰、简洁的方式实现复杂的网页布局,本文给... 目录深入探讨 css3 布局样式及其应用引言一、CSS布局的历史与发展1.1 早期布局的局限性1.2