#1015 : KMP算法
2015-09-04 18:15
288 查看
时间限制:1000ms
单点时限:1000ms
内存限制:256MB
单点时限:1000ms
内存限制:256MB
描述
小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进。这一天,他们遇到了一只河蟹,于是河蟹就向小Hi和小Ho提出了那个经典的问题:“小Hi和小Ho,你们能不能够判断一段文字(原串)里面是不是存在那么一些……特殊……的文字(模式串)?”小Hi和小Ho仔细思考了一下,觉得只能想到很简单的做法,但是又觉得既然河蟹先生这么说了,就肯定不会这么容易的让他们回答了,于是他们只能说道:“抱歉,河蟹先生,我们只能想到时间复杂度为(文本长度 * 特殊文字总长度)的方法,即对于每个模式串分开判断,然后依次枚举起始位置并检查是否能够匹配,但是这不是您想要的方法是吧?”河蟹点了点头,说道:”看来你们的水平还有待提高,这样吧,如果我说只有一个特殊文字,你能不能做到呢?“小Ho这时候还有点晕晕乎乎的,但是小Hi很快开口道:”我知道!这就是一个很经典的模式匹配问题!可以使用KMP算法进行求解!“河蟹满意的点了点头,对小Hi说道:”既然你知道就好办了,你去把小Ho教会,下周我有重要的任务交给你们!“”保证完成任务!”小Hi点头道。输入
第一行一个整数N,表示测试数据组数。接下来的N*2行,每两行表示一个测试数据。在每一个测试数据中,第一行为模式串,由不超过10^4个大写字母组成,第二行为原串,由不超过10^6个大写字母组成。其中N<=20输出
对于每一个测试数据,按照它们在输入中出现的顺序输出一行Ans,表示模式串在原串中出现的次数。样例输入5 HA HAHAHA WQN WQN ADA ADADADA BABABB BABABABABABABABABB DAD ADDAADAADDAAADAAD 样例输出
3 1 3 1 0 提示和题目连接:http://hihocoder.com/problemset/problem/1015 解答: 通过查阅资料发现了四种进行字符串匹配的算法,分别为朴素算法、Rabin-Karp、有限自动机算法、Knuth-Morris-Pratt算法
设定已知条件:已知模式P[1..m]需要匹配的文本T[1..n] 首先说朴素算法,朴素算法真的很朴素,就是通过一个循环来寻找有效的移位,该循环对n-m+1个可能的每一个移位值s进行匹配检查P[1..m]=T[s+1..s+m] 算法伪码:
NAIVE-STRING-MATCHER(T,P) n <- length[T] m <- length[P] for s <- 0 to n-m do if P[1..m] = T[s+1..s+m] then print"找到一个匹配的模式"下面暂时略过Rabin-Karp算法,回头补上,有限自动机算法: 这个算法的步骤就是根据模式P生成一个状态变迁函数,也可以绘出一个状态变迁图例如模式P = {ababaca}就是可以定义7个状态注:对于长度为n的字符串模式,一般定义n+1个状态,其中包含一个初始状态和一个接受状态,在接受状态意味着一个匹配的成功。继续上面模式P的变迁图建立: 这个是对应于模式P={ababaca}的状态转换图,图中浅蓝的标号0的点为起始状态,红色的标号为0的点为接受状态,图中未画出的输入对应的线均指向状态0. 在状态0位置,输入a时,此时字符串a的最长后缀对应P的最长前缀字符串a,长度为1,状态转移到1;输入b时,对应的最长前缀字符串长度为0,c时也是 在状态1位置,输入a时,此时字符串aa的最长后缀对应P的最长前缀字符串为a,长度为1,状态转移到1;输入b时,此时字符串ab的最长后缀对应P的最长前缀字符串为ab,长度为2,所以状态转移到2;当输入c时,字符串ac的最长后缀对应P的最长前缀字符串为空,长度为0,状态转移到0。 ...... 在状态7位置,到达接受状态,即此时已经出现了一次成功匹配,开始下一轮,再输入一个字符a时状态转移到1,输入b时状态转移到2上述即为有限状态机的建立过程,由此可知,当对应模式P的有限状态机建立后,对于文本T的判断是线性的,只需要对于每一个字符输入后的状态变迁,每次到达接受状态就完成一次成功的匹配。KMP算法: KMP算法的关键在于找到模式P的前缀函数next。 在此以模式P={ababababca}为例,阐述一下KMP前缀函数的建立意义。考察朴素的字符串匹配算法的操作过程,当上述模式当中前四个字符匹配成功后,如果第五个字符匹配失败,说明第文本中对应的第五个字符不是a(建议在纸上画一下),还说明了对应的四个字符为abab,将P右移一个位置发现仍然不匹配,右移两个、三个、四个也是,但是右移五个未必。因此能否不像上述方法那样一步一步右移,而是直接右移五个位置开始进行判断。其实在上面匹配过程当中,每次成功的匹配就包含了一定量的信息,而分析模式当中ab的重复也可给人以匹配失败后,可否每次移动两个位置再进行匹配的启发,这样充分发掘模式本身的特点可以建立一个next函数,从而确定每次匹配失败后移动的长度。对于上述模式P发掘的next函数为伪代码如下:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <string> #include <vector> using namespace std; int KMP(string t, string p){ int n = p.size(); vector <int> next(n+1, 0); for(int i=1; i<n; i++){ int j=i; while(j > 0){ j = next[j]; if(p[j] == p[i]){ next[i+1] = j + 1; break; } } } int ans = 0; int m = t.size(); for(int i=0, j=0; i<m; i++){ if(j < n && t[i] == p[j]) j++; else{ while(j > 0){ j = next[j]; if(t[i] == p[j]){ j++; break; } } } if(j == n) ans ++; } return ans; } int main(){ string t, p; int n; scanf("%d", &n); while(n--){ cin>>p>>t; cout<<KMP(t, p)<<endl; } return 0; }
相关文章推荐
- 判断数组是否存在重复元素
- 类加载器详解
- hdu4990Reading comprehension 矩阵快速幂
- 升级Xcode之后VVDocumenter-Xcode不能用的解决办法
- LA 3516 Exploring Pyramids 记忆化搜索
- javaSE基础编程——自定义线程
- ELF文件的加载和动态链接过程
- Unity3D学习笔记《Space Shooter》三
- Java并发编程(Callable、Future和CompletionService)
- 面向对象之设计模式的先行军
- LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
- Apache Camel的Header、Property、Body配置示例
- iOS 用post保障传参数的据安全
- 2015第36周六
- 第八集:asp.net登录页面之验证码
- servlet是单例的 所以需要线程安全 以及如何实现线程安全
- SEO优化方式
- 计算机的容量单位
- 监视网络接口TCP状态信息数据有多种工具或命令。下面举例一些:
- 【修正版】Python基础学习(一)——安装与配置python2.7.x环境(linux)