- 浏览: 202516 次
- 性别:
- 来自: 武汉
文章分类
- 全部博客 (137)
- c++ (74)
- c++,算法,回溯 (2)
- DP问题。 (9)
- DP问题,0/1背包问题 (3)
- 数学问题 (6)
- 贪心算法 (10)
- 排序 (16)
- 数据结构 (7)
- 容器 (2)
- 模拟问题 (2)
- 水题 (8)
- 并查集 (3)
- 非技术 (2)
- 素数问题 (1)
- DFS (3)
- 二叉树 (1)
- 递归 (1)
- 图论 (5)
- 最小生成树 (5)
- 最短路径 (6)
- bell_flaod算法 (2)
- hash (3)
- 二分查找 (1)
- 搜索 (5)
- BFS (5)
- STL (3)
- 字符串hash (1)
- 拓扑排序 (1)
- 字典树 (4)
- 哈弗曼树 (1)
- KMP (7)
- 线段树 (9)
- 树状数组 (6)
- 全排列 (2)
- DP问题 (2)
- LCS (1)
- 最长不下降子序列 (2)
- 面试经验 (3)
字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法。简单匹配算法的时间复杂度为O(m*n);KMP匹配算法。可以证明它的时间复杂度为O(m+n).。 一:让我们先来看基本的简单匹配算法: 先来看一个简单匹配算法的函数:
此算法的思想是直截了当的:将主串S中某个位置i起始的子串和模式串T相比较。即从 j=0 起比较S[i+j] 与 T[j],若相等,则在主串 S 中存在以 i 为起始位置匹配成功的可能性,继续往后比较( j逐步增1 ),直至与T串中最后一个字符相等为止,否则改从S串的下一个字符起重新开始进行下一轮的"匹配",即将串T向后滑动一位,即 i 增1,而 j 退回至0,重新开始新一轮的匹配。
当这样一个失配发生时,T下标必须回溯到开始,S下标回溯的长度与T相同,然后S下标增1,然后再次比较。如图:这次立刻发生了失配,T下标又回溯到开始,S下标增1,然后再次比较。如图:
这次立刻发生了失配,T下标又回溯到开始,S下标增1,然后再次比较。如图:
又一次发生了失配,所以T下标又回溯到开始,S下标增1,然后再次比较。这次T中的所有字符都和S中相应的字符匹配了。函数返回T在S中的起始下标3。如图: int Index_BF ( char S [ ], char T [ ], int pos )
{
/* 若串 S 中从第pos(S 的下标0≤pos<StrLength(S))个字符
起存在和串 T 相同的子串,则称匹配成功,返回第一个
这样的子串在串 S 中的下标,否则返回 -1 */
int i = pos, j = 0;
while ( S[i+j] != '/0'&& T[j] != '/0')
if ( S[i+j] == T[j] )
j ++; // 继续比较后一字符
else
{
i ++; j = 0; // 重新开始新的一轮匹配
}
if ( T[j] == '/0')
return i; // 匹配成功 返回下标
else
return -1; // 串S中(第pos个字符起)不存在和串T相同的子串
}
二 KMP算法
还是相同的例子,在S=”abcabcabdabba”中查找T=”abcabd”,如果使用KMP匹配算法,当第一次搜索到S[5] 和T[5]不等后,S下标不是回溯到1,T下标也不是回溯到开始,而是根据T中T[5]==’d’的模式函数值(next[5]=2,为什么?后面讲),直接比较S[5] 和T[2]是否相等,因为相等,S和T的下标同时增加;因为又相等,S和T的下标又同时增加。。。最终在S中找到了T。如图:
KMP匹配算法和简单匹配算法效率比较,一个极端的例子是: 在S=“AAAAAA…AAB“(100个A)中查找T=”AAAAAAAAAB”, 简单匹配算法每次都是比较到T的结尾,发现字符不同,然后T的下标回溯到开始,S的下标也要回溯相同长度后增1,继续比较。如果使用KMP匹配算法,就不必回溯. 对于一般文稿中串的匹配,简单匹配算法的时间复杂度可降为O (m+n),因此在多数的实际应用场合下被应用。 KMP算法的核心思想是利用已经得到的部分匹配信息来进行后面的匹配过程。看前面的例子。为什么T[5]==’d’的模式函数值等于2(next[5]=2),其实这个2表示T[5]==’d’的前面有2个字符和开始的两个字符相同,且T[5]==’d’不等于开始的两个字符之后的第三个字符(T[2]=’c’).如图:
也就是说,如果开始的两个字符之后的第三个字符也为’d’,那么,尽管T[5]==’d’的前面有2个字符和开始的两个字符相同,T[5]==’d’的模式函数值也不为2,而是为0。 前面我说:在S=”abcabcabdabba”中查找T=”abcabd”,如果使用KMP匹配算法,当第一次搜索到S[5] 和T[5]不等后,S下标不是回溯到1,T下标也不是回溯到开始,而是根据T中T[5]==’d’的模式函数值,直接比较S[5] 和T[2]是否相等。。。为什么可以这样? 刚才我又说:“(next[5]=2),其实这个2表示T[5]==’d’的前面有2个字符和开始的两个字符相同”。请看图 :因为,S[4] ==T[4],S[3] ==T[3],根据next[5]=2,有T[3]==T[0],T[4] ==T[1],所以S[3]==T[0],S[4] ==T[1](两对相当于间接比较过了),因此,接下来比较S[5] 和T[2]是否相等。。。
有人可能会问:S[3]和T[0],S[4] 和T[1]是根据next[5]=2间接比较相等,那S[1]和T[0],S[2]和T[0]之间又是怎么跳过,可以不比较呢?因为S[0]=T[0],S[1]=T[1],S[2]=T[2],而T[0] != T[1], T[1] != T[2],==> S[0] != S[1],S[1] != S[2],所以S[1] != T[0],S[2] != T[0]. 还是从理论上间接比较了。 有人疑问又来了,你分析的是不是特殊轻况啊。 假设S不变,在S中搜索T=“abaabd”呢?答:这种情况,当比较到S[2]和T[2]时,发现不等,就去看next[2]的值,next[2]=-1,意思是S[2]已经和T[0] 间接比较过了,不相等,接下来去比较S[3]和T[0]吧。 假设S不变,在S中搜索T=“abbabd”呢?答:这种情况当比较到S[2]和T[2]时,发现不等,就去看next[2]的值,next[2]=0,意思是S[2]已经和T[2]比较过了,不相等,接下来去比较S[2]和T[0]吧。 假设S=”abaabcabdabba”在S中搜索T=“abaabd”呢?答:这种情况当比较到S[5]和T[5]时,发现不等,就去看next[5]的值,next[5]=2,意思是前面的比较过了,其中,S[5]的前面有两个字符和T的开始两个相等,接下来去比较S[5]和T[2]吧。 总之,有了串的next值,一切搞定。那么,怎么求串的模式函数值next[n]呢?(本文中next值、模式函数值、模式值是一个意思。)
意义:
next 函数值究竟是什么含义,前面说过一些,这里总结。
设在字符串S中查找模式串T,若S[m]!=T[n],那么,取T[n]的模式函数值next[n],
1. next[n]= -1 表示S[m]和T[0]间接比较过了,不相等,下一次比较 S[m+1] 和T[0]
2. next[n]=0 表示比较过程中产生了不相等,下一次比较 S[m] 和T[0]。
3. next[n]= k >0 但k<n, 表示,S[m]的前k个字符与T中的开始k个字符已经间接比较相等了,下一次比较S[m]和T[k]相等吗?
4. 其他值,不可能。
怎么样求next[k]代码模板如下:
void get_next()
{
int j=1, k=0;
next[0]=-1;
next[1]=0;
while(j< lenp)
{
if(pat[j] == pat[k])
{
next[j+1]=k+1;
j++;
k++;
}
else if (k==0)
{
next[j+1]=0;
j++;
}
else k=next[k];
}
}
模式匹配过程是这样:
当模式串t中的tj与主串中的si比较不相等时,若模式串中存在真子串"t0t1...tk-1"="tj-ktj-k+1...tj-1",此时可以将模式串t按照k=next[j]的值右移,然后比较si与tk(仔细想想),若仍有si!=tk,则继续按照k=next[k]进行迭代,继续右滑,然后比较si与tk。这样的过程一直进行到k=0,此时,若仍有si!=t0,则比较si+1与t0。
next[j]的值有三种意思:
当串有真子串,为k(0<k<j);
当串无真子串,为0;
当j=0,为-1。
代码模板如下:
int KMP() { int i= 0, j= 0; get_next(); while(i < lent && j < lenp) { if(j == -1 || text[i] == pat[j]) { i ++; j ++; } else j = next[j]; } if(j >= lenp) return i - lenp; else return -1; }
KMP算法的模板如下:
#include<iostream> using namespace std; const int Max = 10000; char text[Max], pat[Max]; int lent, lenp; int next[Max]; void get_next() { int j=1, k=0; next[0]=-1; next[1]=0; while(j< lenp) { if(pat[j] == pat[k]) { next[j+1]=k+1; j++; k++; } else if (k==0) { next[j+1]=0; j++; } else k=next[k]; } } int KMP() { int i= 0, j= 0; get_next(); while(i < lent && j < lenp) { if(j == -1 || text[i] == pat[j]) { i ++; j ++; } else j = next[j]; } if(j >= lenp) return i - lenp; else return -1; } int main() { scanf("%s%s", text, pat); lent = strlen(text); lenp = strlen(pat); printf("%d\n", KMP()); return 0; }
至于2406: 题意:给出一个串,问你这个最多是多少个相同的字串重复连接而成的。如:ababab则最多有3个ab连接而成。
思路:KMP中的get_next(),或者get_nextval(),对next数组的应用。next[len]是最后一个字符跳的步长,如果他有相同字符串,则该串长度是len-next[len](这点我还在想要怎么证明!)...如果整个长度len能分解成x个这种串(能整除),就得到ans了。否则不能分解。只能是由他自己组成串,长度为1。
代码如下:
#include<iostream> #include<string> using namespace std; const int Max = 100000005; char str[Max]; // 模式串。 int len, next[Max]; void get_next() { int j=1, k = 0; next[0]=-1; next[1]=0; while(j < len) { if(str[j] == str[k]) { next[j+1]=k+1; j++; k++; } else if (k==0) { next[j+1]=0; j++; } else k= next[k]; } } int main() { while(scanf("%s", str) != EOF) { if(str[0] == '.') break; len = strlen(str); get_next(); int ans = 1; if(len % (len-next[len]) == 0) // 看整个长度len能分解成x个这种串。 ans = len / (len-next[len]); printf("%d\n", ans); } return 0; }
关于KMP算法的理解需要自己慢慢去体会~~
发表评论
-
poj 2185
2012-07-05 15:10 1178题意:给你一个字符矩阵,求出它的最小覆盖子矩阵,即使得 ... -
poj 3450
2012-07-05 11:03 846题意:给你n个的串,求出它们的最长公共子串,如果不存在 ... -
poj 3080
2012-07-05 10:48 918题意:给你n个长度都为60的串,求出它们的最长公共子串 ... -
poj 3461
2012-06-27 19:48 738题意:给你一个字串(模式串)和一个母串(文本),问字串在母串中 ... -
poj 2752
2012-06-27 16:00 2622题意:给你一个串,如果这个串存在一个长度为n的前缀串,和长度为 ... -
poj 1961
2012-06-26 21:06 1265这题可以加深对KMP的懂得!题意:给出一个字符串,对于它的每个 ... -
poj 2406
2012-06-25 21:01 0当这样一个失配发生时,T下标必须回溯到开始,S下标回 ...
相关推荐
#include using namespace std; #define M 1000000 char t[M+1],p[M+1]; int lent,lenp; bool kmp(char *t,char *p) { int i,j; for(i=lenp,j=0;i;i++) { if(t[i]!=p[j]) return false;...}
* KMP 算法:例如 poj1961、poj2406。 4. 搜索: * 最优化剪枝和可行性剪枝。 * 搜索的技巧和优化:例如 poj3411、poj1724。 * 记忆化搜索:例如 poj3373、poj1691。 5. 动态规划: * 较为复杂的动态规划:...
例如,题目poj1961和poj2406就是KMP算法的应用实例。 ### 7. 几何算法 几何算法涉及点、线、面的性质和关系,如凸包、最近点对、三角剖分等问题。这些算法在计算机图形学、地理信息系统等领域有着广泛的应用。例如...
- (poj1961, poj2406):高效的字符串匹配算法。 ### 十、进阶状态压缩 1. **状态压缩技巧**: - 如何高效地表示和压缩状态。 2. **状态压缩优化**: - (poj3411, poj1724):进一步提高状态压缩动态规划的效率...
- POJ 1961、POJ 2406:KMP算法的应用。 ### 其他问题 #### 贪心算法 - **题目示例**: - POJ 3411、POJ 1724:贪心策略的选择与应用。 #### 二分查找 - **题目示例**: - POJ 3373、POJ 1691:二分查找技术的...
- 推荐题目:[poj1961](https://vjudge.net/problem/POJ-1961)、[poj2406](https://vjudge.net/problem/POJ-2406) - 字符串匹配算法如KMP算法可以提高字符串匹配的效率。 以上列举的题目只是冰山一角,POJ上还有...
5. **字符串匹配**:如KMP算法(poj1961, poj2406)。 ### 十三、进阶算法 1. **组合优化**:如割平面法、分支定界法等(poj3411, poj1724)。 2. **近似算法**:解决NP难问题时的近似求解方法(poj3373, poj1691...
* KMP算法:POJ1961、POJ2406 * 左偏树(可合并堆) 四、搜索 * 最优化剪枝和可行性剪枝 * 较为复杂的动态规划:POJ1191、POJ1054、POJ3280、POJ2029、POJ2948、POJ1925、POJ3034 * 记录状态的动态规划:POJ3254、...
ACM常用算法及其相应的练习题 本资源总结了 ACM 竞赛中常用的算法和相应的练习题,涵盖了基础算法、图算法、数据... + poj1961, poj2406 四、搜索 * 最优化剪枝和可行性剪枝 * 搜索的技巧和优化 + poj3411, poj1724
3. KMP 算法(poj1961, poj2406) 4. 左偏树(可合并堆) 四、搜索 1. 最优化剪枝和可行性剪枝 2. 较为复杂的动态规划(如动态规划解特别的施行商问题等) 3. 记录状态的动态规划 4. 树型动态规划 五、计算几何学...
- 示例题目:poj1961, poj2406 #### 高级动态规划 1. **矩阵乘法** - 示例题目:poj1191, poj1054, poj3280, poj2029, poj2948, poj1925, poj3034 2. **四边形不等式** - 示例题目:POJ3254, poj2411, poj1185...
- **示例题目**: POJ 3267, POJ 1836, POJ 1260, POJ 2533, POJ 3176, POJ 1080, POJ 1159 - **注意事项**: 理解每种模型的状态定义和转移方程。 #### 六、数学 **1. 组合数学** - **定义**: 研究组合结构的...
6. **KMP算法**(如poj1961, poj2406):高效的字符串匹配算法,适用于文本检索、模式识别等领域。 #### 优化技巧 1. **代码优化**(如poj3096, poj3007):包括循环展开、条件判断优化等,提高代码执行效率。 2. ...
poj平台有关数据结构题的Java源码 1159 1276 2406 2502 2509 2513 2533 2778 3176
* 短代码:1147、1163、1922、2211、2215、2229、2232、2234、2242、2245、2262、2301、2309、2313、2334、2346、2348、2350、2352、2381、2405、2406 * 中短代码:1014、1281、1618、1928、1961、2054、2082、2085...
* 2406 Power Strings * 2339 Rock, Scissors, Paper * 2350 Above Average * 2218 Does This Make Me Look Fat? * 2260 Error Correction * 2262 Goldbach's Conjecture * 2272 Bullseye 博弈类 博弈类题目是 POJ...
1129 1149 1154 1165 1182 1185 1190 1191 1201 1251 1273 1275 1276 1286 1322 1338 1363 1364 1401 1456 1459 1564 1579 1637 1657 1658 1679 ...2104 2112 2115 2186 2255 2352 2369 2406 2409 2421 2479 2480 2498
1001 1002 1003 1004 1005 1006 1007 1008 1011 1012 1013 1014 1015 1017 ...2406 2411 2418 2421 2441 2479 2485 2487 2488 2506 2513 2521 2524 2533 2538 2545 2550 2551 2560 2591 2593 2601 2608 2626 2636 2643 ...
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1011 1012 1013 1014 ...2406 2411 2413 2419 2421 2446 2449 2456 2479 2488 2492 2503 2509 2513 2524 2528 2531 2533 2545 2553 2559 2564 2575 2576 2586 2591 ...
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1011 1012 1013 1014 ...2406 2411 2421 2479 2524 2576 2707 2777 2812 2818 2840 3168 3219 3224 3250 3253 3278 3302 3311 3312 3325 3348 3349 3355 3357 3372 ...