KMP算法
KMP算法是一种字符串模式匹配算法。
什么是字符串的模式匹配?
给定两个串S=“s1s2s3 …sm”和T=“t1t2t3 …tn”,在主串S中寻找子串T的过程叫做模式匹配,T称为模式。
暴力匹配(朴素模式匹配BF)
规定i是主串S的下标,j是模式T的下标。现在假设现在主串S匹配到 i 位置,模式串T匹配到 j 位置。
如果当前字符匹配成功(即S[i] = T[j]),则i++,j++,继续匹配下一个字符;
如果失配(即S[i] != T[j]),令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯到本次失配起始字符的下一个字符,j 回溯到0。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | int BF( char S[], char T[]) { int i=0,j=0; while (S[i]!= '\0' &&T[j]!= '\0' ) { if (S[i]==T[j]) { i++; j++; } else { i=i-j+1; j=0; } } if (T[j]== '\0' ) return (i-j); //主串中存在该模式返回下标号 else return -1; //主串中不存在该模式 } |
1. 背景KMP算法一种改进的模式匹配算法,是D.E.Knuth、V.R.Pratt、J.H.Morris于1977年联合发表,KMP算法又称克努特-莫里斯-普拉特操作。它的改进在于:每当从某个起始位置开始一趟比较后,在匹配过程中出现失配,不回溯i,而是利用已经得到的部分匹配结果,将一种假想的位置定位“指针”在模式上向右滑动尽可能远的一段距离到某个位置后,继续按规则进行下一次的比较。
前缀与后缀
前缀:含有首字符不含尾字符的所有子串。
后缀:含有尾字符不含首字符的所有子串。
最长相等前后缀的长度next数组
现在有串P=abaabca,各个子串的最大相等前后缀长度如下表所示:
这样,最长相等前后缀最长长度就会和串P的每个字符产生一种对应关系:
这个表的含义是在当前字符作为最后一个字符时,当前子串所拥有的公共前后缀最长长度。例如当c作为最后一个字符时,当前子串abaabc并没有公共前后缀。
接下来我们就用这个表来引出next数组,next 数组的值是公共前后缀最长长度。我们称next数组中的值为失效函数值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #include<iostream> #include<string> using namespace std; void getnext( int *next, string &s) { int i,j; next[0]=0; j=0; for ( int i=1;i<s.size();i++) { while (j>0&&s[j]!=s[i]) { j=next[j-1]; } if (s[j]==s[i]) j++; next[i]=j; } } int Kmp( string s, string t) { int *next; next= new int [s.size()+1]; getnext(next,s); int i=0,j=0; for (i=0;i<t.size();i++) { while (j>0&&s[j]!=t[i]) { j=next[j-1]; } if (s[j]==t[i]){ j++; } if (j==s.size()) { return i-j+1; } } return -1; } int main() { string s,t; cin>>t; cin>>s; cout<<Kmp(s,t)<<endl; } /* in babaabaabaafg aabaaf out 6 */ |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?