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. AIDL/IPC Android AIDL/IPC 进程通信机制——超具体解说及使用方法案例剖析(播放器)

    首先引申下AIDL.什么是AIDL呢?IPC? ------ Designing a Remote Interface Using AIDL 通常情况下,我们在同一进程内会使用Binder.Broad ...

  2. 搭建Maven私服(使用Nexus)

    搭建私服能够做什么? 1.假设公司开发组的开发环境所有内网.这时怎样连接到在互联网上的Maven中央仓库呢? 2.假设公司常常开发一些公共的组件.怎样共享给各个开发组.使用拷贝方式吗?假设这样,公共库 ...

  3. Spark调研笔记第3篇 - Spark集群相应用的调度策略简单介绍

    Spark集群的调度分应用间调度和应用内调度两种情况,下文分别进行说明. 1. 应用间调度 1) 调度策略1: 资源静态分区 资源静态分区是指整个集群的资源被预先划分为多个partitions,资源分 ...

  4. Android多线程更新UI的方式

    Android下,对于耗时的操作要放到子线程中,要不然会残生ANR,本次我们就来学习一下Android多线程更新UI的方式. 首先我们来认识一下anr: anr:application not rep ...

  5. SSH三大框架整合配置详细步骤(2)

    4 配置Hibernate Hibernate MySql连接配置 在Hibernate中,可以配置很多种数据库,例如MySql.Sql Server和Oracle,Hibernate MySql连接 ...

  6. 用css解决Unigui在IE系列浏览器中字体变小的问题(设置UniServeModule的customcss属性)

    Unigui运行在chrome浏览器下可以有最佳的效果,但用ie打开用unigui做的项目会发现字体明显小一截,可以用自定义css来解决这个问题. 可以在UniServeModule的customcs ...

  7. Revit插件开发HelloWorld

    1. 使用 VS2012 先建立一个项目. 2. 在这里我们选择建立C# 类库项目, 改动项目名称为HelloWorld. 能够自己定义改动项目存放路径. 3. 加入 Revit 插件 API 的引用 ...

  8. shell系统管理

    背景知识 对于 Linux 系统管理员来说,没有比 shell 脚本编程更有用处的了.通常,Linux 系统管理员每天需要完成无数项任务,从监视系统磁盘空间和系统用户到备份重要文件.Shell 脚本可 ...

  9. Golang1.8编译静态库给C使用

    Go实例代码: package main import ( "fmt" ) import "C" //export Printf func Printf(for ...

  10. Iterator 使用

    Configuration cfg = new Configuration().configure(); SessionFactory factory = cfg.buildSessionFactor ...