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

相关文章

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

将Python应用部署到生产环境的小技巧分享

《将Python应用部署到生产环境的小技巧分享》文章主要讲述了在将Python应用程序部署到生产环境之前,需要进行的准备工作和最佳实践,包括心态调整、代码审查、测试覆盖率提升、配置文件优化、日志记录完... 目录部署前夜:从开发到生产的心理准备与检查清单环境搭建:打造稳固的应用运行平台自动化流水线:让部署像

Linux中Curl参数详解实践应用

《Linux中Curl参数详解实践应用》在现代网络开发和运维工作中,curl命令是一个不可或缺的工具,它是一个利用URL语法在命令行下工作的文件传输工具,支持多种协议,如HTTP、HTTPS、FTP等... 目录引言一、基础请求参数1. -X 或 --request2. -d 或 --data3. -H 或

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

java中VO PO DTO POJO BO DO对象的应用场景及使用方式

《java中VOPODTOPOJOBODO对象的应用场景及使用方式》文章介绍了Java开发中常用的几种对象类型及其应用场景,包括VO、PO、DTO、POJO、BO和DO等,并通过示例说明了它... 目录Java中VO PO DTO POJO BO DO对象的应用VO (View Object) - 视图对象

Go信号处理如何优雅地关闭你的应用

《Go信号处理如何优雅地关闭你的应用》Go中的优雅关闭机制使得在应用程序接收到终止信号时,能够进行平滑的资源清理,通过使用context来管理goroutine的生命周期,结合signal... 目录1. 什么是信号处理?2. 如何优雅地关闭 Go 应用?3. 代码实现3.1 基本的信号捕获和优雅关闭3.2