Problem Description

一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?

Input

输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。

Output

输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。

Sample Input

abcde a3
aaaaaa aa
#

Sample Output

0
3

解题思路:这是一道KMP入门题,设计出这个算法的人真的太聪明了,字符串匹配过程真的太巧妙了!!!这道题就是给你一个主串和一个模式串,要求从主串找出没有交集的模式串的最大数量。一开始很容易想到暴力枚举,不过会超时,时间复杂度是O(nm),还不如花多点时间学习新的算法思想,争取在做题中灵活应用。对于KMP的讲解,目前有一篇大牛写的算是賊好理解了,这个算法时间复杂度是O(n+m),传送门:KMP算法最浅显理解——一看就明白

AC代码一:

 #include<bits/stdc++.h>
using namespace std;
char text[],pattern[];//主串,模式串,问主串中能截取出多少个模式串,取出后再从后面的子串中查找
int prefix[],lena,lenb,num; //prefix[i]记录的是前i-1个字符构成的子串中最长公共前后缀长度
void get_prefix_table(){//处理模式串的前缀表
int j=,pos=-;
prefix[]=-;//prefix[0]初始化为-1,-1表示不存在相同的最大前缀和最大后缀,即模式串第一个字符前面不存在子串
while(j<lenb){
if(pos==-||pattern[pos]==pattern[j])prefix[++j]=++pos;//当pos为-1时,++j,++pos表示下一个字符前的子串的最长公共前后缀长度为0
else pos=prefix[pos];//如果当前j指向的字符和pos指向的字符不同,则pos退回到pos指向下标为当前pos位置前面子串的最长公共前后缀长度的字符,再次进行比较
}
}
void kmp_search(){//从主串中能截取出多少模式串,不叠加计算
int i=,j=;//i从主串下标为0开始,j从模式串下标为0开始
while(i<lena){
if(j==-||text[i]==pattern[j])i++,j++;//如果j==-1,说明主串中i位置前面的子串与模式串没有交集,即前者的后缀和后者的前缀不相等,则同时右移一位
else j=prefix[j];//j退回到j指向下标为模式串中当前j位置前面子串的最长公共前后缀长度的字符,再次进行比较
if(j==lenb)num++,j=;//如果j等于模式串的长度,则计数器加1,并且j重置为0,再寻找主串中后面的子串是否还包含模式串
}
}
int main(){
while(~scanf("%s",text)&&strcmp(text,"#")){
scanf("%s",pattern);
memset(prefix,,sizeof(prefix));
num=,lena=strlen(text),lenb=strlen(pattern);
get_prefix_table();
kmp_search();
printf("%d\n",num);
}
return ;
}

代码过程简单分析:如上所示,我们先对模式串进行打印前缀表,然后再调用kmp_search()来与主串匹配。这里给一串模式串abaabcac计算其前缀表。首先我们定义prefix[0]=-1,表示模式串第1个字符前面的子串的最长公共前后缀长度不存在,定义为-1,待循环模式串到j,如果第j个字符pattern[j]!=pattern[pos],pos退回到下标为第pos个字符前面的子串的最长公共前后缀长度,再次比较,如果继续不等,pos将会退回到-1,这时满足if语句则执行prefix[++j]==0,表示下一个字符前面的子串的最长公共前后缀长度为0,为什么是先计算下一个字符的prefix[j]呢?这是为了代码好写,简洁一些,巧妙处理前缀表,所以给出模式串的前缀表如下:

模式串的下标               0  1  2  3  4  5  6  7

模式串                          a  b  a  a  b  c  a  c

前缀表下标               0  1  2  3  4  5  6  7  8

最长公共前后缀长度    -1  0  0  1  1  2  0  1  0

注意上面前缀表与模式串对应的下标位置。计算好模式串的前缀表之后,开始与主串进行匹配了,用i,j分别指向主串,模式串的当前位置,当匹配失败时,指针i(指向主串)不变,指针j(指向模式串)退回到prefix[j]所指示的位置上重新进行比较,并且当j退至-1时,指针i和指针j需同时增1。即若主串的第i个字符和模式串的第j个字符不等,应从主串的第i+1个字符重新进行匹配。

上面给的大牛博客里讲的很清楚了,为什么j要退回到prefix[j],这里谈谈我的学习心得:prefix[j]记录的是前j-1个字符组成的子串的最长前后缀公共长度。举个栗子:仍用上面的模式串,假设现在我们要求最后的'c'字符下的prefix[8],怎么求呢?已知prefix[7]=1,说明'c'字符前面的字符串abaabca其最长公共前后缀长度为1,这时我们加上了字符'c',那么只需比较最前面的第1个字符'a'后面字符'b'是否等于当前字符'c',即判断pattern[j=1]==pattern[i=7]?如果相等的话就执行prefix[7+1]=prefix[8]=1+1=2(表示最后一个字符的下一个位置前面的子串的最长公共前后缀长度是2),否则j=prefix[j=1]=0,很明显,pattern[j=0]!=pattern[i=7],所以j继续退回j=prefix[j=0]=-1,这时说明字符'c'已不能与第一个字符'a'前面的字符进行匹配,满足if语句,即prefix[8]=-1+1=0。接下来进行模式串与主串的匹配,其匹配模式和计算前缀表所用的方法基本一样,多了一步判断j(j是从0开始计算的)是否达到模式串尾,即判断j==lenb?如果是,计数器加1,并且j重置为0,即从模式串第一个字符开始,再在主串中剩下的子串中查找模式串。

解法2:这道题要求找主串中含有的不相交模式串的数量,那么可以运用库函数strstr()来计数num。

strstr 语法:头文件#include <string.h>

char *strstr( const char *str1, const char *str2 );

功能:函数返回一个指针,它指向字符串str2 首次出现在字符串str1中的位置,如果没有找到,返回NULL。

解题思路:通过这个函数的特点,因为返回的是地址,所以我们定义一个字符指针p来指向接受返回地址,如果找到的话,加上模式串的长度,再接下去寻找是否含有模式串,如果找不到的话,返回NULL将会退出当前循环。

AC代码二:

 #include <bits/stdc++.h>
using namespace std;
char *p,text[],pattern[];int len,num;
int main(){
while(cin>>text&&strcmp(text,"#")){
cin>>pattern;
num=,len=strlen(pattern);
for(p=text;(p=strstr(p,pattern))!=NULL;num++,p+=len);
cout<<num<<endl;
}
return ;
}

题解报告:hdu 2087 剪花布条(KMP入门)的更多相关文章

  1. hdu 2087剪花布条 (KMP入门 子串出现的次数和子串个数)

    剪花布条 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  2. HDU 2087 - 剪花布条 - [KMP算法]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 Time Limit: 1000/1000 MS (Java/Others) Memory Li ...

  3. HDU 2087 剪花布条 (KMP 不允许重叠的匹配)

    题目链接 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢? Inp ...

  4. HDU 2087 剪花布条(字符串匹配,KMP)

    HDU 2087 剪花布条(字符串匹配,KMP) Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出 ...

  5. HDU 2087 剪花布条 (简单KMP或者暴力)

    剪花布条 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  6. HDU 2087 剪花布条 (字符串哈希)

    http://acm.hdu.edu.cn/showproblem.php?pid=2087 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图 ...

  7. HDU 2087 剪花布条【在字符串中不可重叠地寻找子串数量】

    一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?  Input输入中含有一些数据,分别是成对出现的花布条和 ...

  8. HDU 2087 剪花布条 KMP入门

    Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条.计算一下能从花布条中尽可能剪出几块小饰条来呢?   Input ...

  9. HDU 2087 剪花布条(模式串在主串中出现的次数主串中子串不可重叠)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 题意:求模式串在主串中出现的次数,与模式串匹配的子串之间不可重叠. 思路:用kmp算法解决,在匹 ...

  10. HDU 2087 剪花布条 KMP极其初级之入门题(KMP模板在这里)

    Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?   Input ...

随机推荐

  1. 【c++】动态内存

    静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.它主要存放静态数据.全局数据和常量.注意:const常量在定义时必须初始化 栈区:在执行函数时,函数内局部变量的存储单 ...

  2. Error Code: 2006 - MySQL 鏈嶅姟鍣ㄥ凡绂荤嚎

    将sql文件导入到mysql时候,就一直报这个错误. 我试过网上各种方法都行不通. 最后将以下一句运行了一下就能够了,并且没有重新启动mysql. SET GLOBAL max_allowed_pac ...

  3. github的提交源码到服务器

    github是现代的代码库,各种牛人,各种开源,也是现在大公司招聘的一个考察点, 这里介绍一下怎样把本地源码提交到github上. 首先我们需要在github上创建一个respository. 2,输 ...

  4. 2016/3/1 淘宝 腾讯 网易 css初始化代码 以及最基础的初始化

    淘宝官网(http://www.taobao.com/)样式初始化 body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, o ...

  5. 更改Mysql登录密码

    版本号49之前的跨域设置 在Windows命令行下修改mysql数据库密码步骤如下: 1.通过dos命令进入mysql的bin目录: 2.输入“mysql -uroot -p”,回车进入mysql命令 ...

  6. 内存溢出-jvisualvm排查问题

    先来一段能够内存溢出的程序 public static void main(String[] args) { List<Object> list = new ArrayList<&g ...

  7. Java之jdk命令行工具详解

    JPS---虚拟机进程状况工具 常用的参数: -l 输出Java应用程序的main class的完整包 -q 仅显示pid,不显示其它任何相关信息 -m 输出传递给main方法的参数 -v 输出传递给 ...

  8. codeforces 739E - Gosha is hunting

    这道题有三种做法,感受一下: 感觉到了歪果仁费尽脑汁想出来的神仙贪心脑洞题被中国人套路算法踩爆的凄凉...(我的名字是不是暴露了我的真实实力) ============================ ...

  9. beyond compare 比较文本 standard alignment VS unaligned

    在Rules里面 Standard Alignment 这种方式会比较找出相同的部分,可能会跨行找相同的 Unaligned 这种比较直接每一行之间相互比较,不跨行找相同的

  10. problem in Sourcetree

    1.The date is commit date not the date of author 2.The log line is ordered  by time, actually it sho ...