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. linux字符驱动之poll机制按键驱动

    在上一节中,我们讲解了如何自动创建设备节点,实现一个中断方式的按键驱动.虽然中断式的驱动,效率是蛮高的,但是大家有没有发现,应用程序的死循环里的读函数是一直在读的:在实际的应用场所里,有没有那么一种情 ...

  2. 用Visual Studio高版本号打开低版本号的project,转换时出现错误:fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

    解决方法是: 在电脑里面搜索发现   C:\Program Files\Microsoft Visual Studio 10.0\VC\bin   C:\Windows\winsxs\x86_netf ...

  3. SGU - 186 - The Chain (贪心)

    186. The Chain time limit per test: 0.25 sec. memory limit per test: 4096 KB input: standard input o ...

  4. jquery全选,取消全选

    近期项目又用到了这个全选和取消全选的操作. 曾经总是自己写纯JS.如今既然知道怎么写了.那怎样用JQ写得更简洁呢.这样也能学到新的东西.假设乎百度一下果然发现了好东东.感谢OSC的iuhoay. 代码 ...

  5. UVA 1400 1400 - &quot;Ray, Pass me the dishes!&quot;(线段树)

    UVA 1400 - "Ray, Pass me the dishes!" option=com_onlinejudge&Itemid=8&page=show_pr ...

  6. 10 逻辑完善以及bug修复

    进行到这里,我们应用开发已经接近尾声,我这里基本就是应用开发的记录过程,讲解的东西很少,有问题可以在评论区讨论呦.下面进入最后调整的阶段. 预览我们的应用,会发现首页的职位列表,也会显示收藏的星星图标 ...

  7. Java中有多少种设计模式?请简单画一下三种常见设计模式的类图?

    转载:http://blog.csdn.net/longyulu/article/details/9159589 一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽 ...

  8. python iterable 和list、dictionary的区别和联系

    1 为什么一些函数的参数指定要iterable object的,但是也可以传入list为参数? 因为list.dictionary都是iterable object. 在iterable object ...

  9. 设计模式-(9)中介者模式(swift)

    在对象去耦合的模式中,有两种模式:中介者模式,观察者模式 一,概念 用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 这个 ...

  10. Hibernate状态转换

    瞬时态: 对象有new关键字创建,此时还未与Session关联. 持久态: 在执行session.save(bean)或saveOrUpdate()操作后,bean纳入Session的管理范围,这时b ...