【hiho一下】第三周 KMP算法
2014-07-27 10:47
471 查看
题目1:KMP算法
题目原文:http://hihocoder.com/contest/hiho3/problem/1
【题目解读】
就是KMP算法的基本使用之一。添加了计数功能。
KMP算法的核心思想,就是通过减少匹配失败时模式串的回溯位数,来减少匹配次数。此时回溯的时候,使用 next 数组。
求解 next 数组见:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html,需要注意的是,这里用到了数学归纳法。即:
假设:根据定义next[0]=-1。然后,假设next[j]=k, 即P[0...k-1]==P[j-k,j-1]
则有:1)若P[j]==P[k],则有P[0..k]==P[j-k,j],很显然,next[j+1]=next[j]+1=k+1;
2)若P[j]!=P[k],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,显然k=next[k]
next 数组的求解,可以视为相错一位的模式串,其中一个作为原始串,另外一个作为模式串,进行匹配,失败则回溯
【编写细节】
(1)想要理解KMP算法的主体比较部分,建议先实现 BF算法,就是最普通的暴力匹配。如下:
对照这个再去写KMP的主题匹配,就能理解 for 里面的第一个while为了找到原始串与模式串的第一个匹配点(不一定是模式串的第一个字符);
(2)KMP里面如果不匹配就回溯(绝不用--),一律使用k = next[k],不会使用到 k--;只要回溯了第一次,之后不匹配即可不断回溯直至找到匹配或者直接到头;
(3)一定要注意!KMP算法需要单独考虑模式串与原始串长度均为1时的情况!次数 next 数组只有一个值-1;
(4)此题是KMP匹配的计数功能,所以需要原始串的一位一位字符扫描(for循环),以防遗漏ABABA中有两个ABA的情况;
(5)其余细节写在代码注释。。。很难搞,当模板记下来吧。
【AC代码】
题目原文:http://hihocoder.com/contest/hiho3/problem/1
【题目解读】
就是KMP算法的基本使用之一。添加了计数功能。
KMP算法的核心思想,就是通过减少匹配失败时模式串的回溯位数,来减少匹配次数。此时回溯的时候,使用 next 数组。
求解 next 数组见:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html,需要注意的是,这里用到了数学归纳法。即:
假设:根据定义next[0]=-1。然后,假设next[j]=k, 即P[0...k-1]==P[j-k,j-1]
则有:1)若P[j]==P[k],则有P[0..k]==P[j-k,j],很显然,next[j+1]=next[j]+1=k+1;
2)若P[j]!=P[k],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,显然k=next[k]
next 数组的求解,可以视为相错一位的模式串,其中一个作为原始串,另外一个作为模式串,进行匹配,失败则回溯
【编写细节】
(1)想要理解KMP算法的主体比较部分,建议先实现 BF算法,就是最普通的暴力匹配。如下:
#include<stdio.h> #include<stdlib.h> #include<string.h> char ori[1000005]; char par[10005]; int next[10005]; int main() { int t; scanf("%d", &t); long olen; int plen; int ans; while(t--) { ans = 0; memset(ori, 0, sizeof(ori)); memset(par, 0, sizeof(par)); memset(next, 0, sizeof(next)); scanf("%s", par); scanf("%s", ori); olen = strlen(ori); plen = strlen(par); for(long i=0; i<olen; i++) { long j = i; int k = 0; while(ori[j] == par[k]) { j++; k++; if(k >= plen) break; } if(k>=plen) ans++; } printf("%d\n", ans); } return 0; }
对照这个再去写KMP的主题匹配,就能理解 for 里面的第一个while为了找到原始串与模式串的第一个匹配点(不一定是模式串的第一个字符);
(2)KMP里面如果不匹配就回溯(绝不用--),一律使用k = next[k],不会使用到 k--;只要回溯了第一次,之后不匹配即可不断回溯直至找到匹配或者直接到头;
(3)一定要注意!KMP算法需要单独考虑模式串与原始串长度均为1时的情况!次数 next 数组只有一个值-1;
(4)此题是KMP匹配的计数功能,所以需要原始串的一位一位字符扫描(for循环),以防遗漏ABABA中有两个ABA的情况;
(5)其余细节写在代码注释。。。很难搞,当模板记下来吧。
【AC代码】
#include<stdio.h> #include<stdlib.h> #include<string.h> char ori[1000005]; char par[10005]; int next[10005]; int t, plen; long olen, ans; void get_next(int len) { next[0] = -1; int j = 0; int k = -1; while(j < len) { // 一直找到可以匹配的开始,或者无法匹配的开头 if(k==-1 || par[j] == par[k]) { // 此时保证j不能已经加过 next[j+1] = k + 1; j++; k++; } else { k = next[k]; } } } int main() { scanf("%d", &t); while(t--) { ans = 0; scanf("%s", par); scanf("%s", ori); plen = strlen(par); olen = strlen(ori); if(olen==1 && plen==1) { if(ori[0] == par[0]) ans = 1; else ans = 0; printf("%d\n", ans); continue; } get_next(plen); int j = 0; for(long i=0; i<olen; i++) { // while的顺序:一定要先找到一个可以匹配的起点 // j>=1杜绝出现next[j]=-1,因此单独考虑 olen=plen=1 while(ori[i] != par[j] && j>=1) { j = next[j]; } if(ori[i] == par[j]) { j++; } // 在找到匹配的第一个字符前,i不能继续++ // else // { // j = next[j]; // } if(j >= plen) { ans++; // 回溯过程中不会遗漏,最差情况从头匹配 j = next[j]; } } printf("%d\n", ans); } return 0; }
相关文章推荐
- hiho hiho一下第三周 #1015 : KMP算法
- (hiho一下第三周)#1015 KMP算法 【模版】
- 【hiho一下 第三周】KMP算法
- hiho一下 第三周 Hiocoder #1015 : KMP算法
- hiho一下 第三周---KMP算法
- hiho一下第三周 kmp算法。
- 【hiho一下第三周】KMP计算模式串在原串出现次数
- hiho一下 第三周 "KMP"算法
- hiho一下 第三周
- hiho第三周——字符串匹配KMP算法
- hiho一下~week_3 KMP算法
- hiho一下第3周#1015 : KMP算法
- hiho一下 第139周 买零食 动态规划
- hiho 第3周 KMP算法(KMP)
- hiho一下 第十五周 最近公共祖先·二 - 更新一下tarjan离线LCA模板
- hiho一下 第十七周 最近公共祖先
- hiho一下 第二十八周 最小生成树三·堆优化的Prim算法
- Eular质数筛法-hiho一下 第九十三周
- hiho一下 第156周 岛屿
- hihocoder hiho一下 第九十五周