- kmp算法可以用作匹配字串问题的朴素算法的改进,相对与朴素的查找O(n^2)的时间复杂度,kmp算法只需要大致为O(n),大大提升了查找速度。
- kmp算法区别于朴素查找的算法的不同点就是它可以更高效的回溯比较。
-
上图第六个字母不同,朴素做法是从主串的第二个开始,重新遍历,而kmp算法更加高效。
-
它跳过了其中不可能的字符遍历,节省了时间,它只对子串进行了回溯,我们注意到不同的是‘=’和‘c’,主串仍然将从这个位置继续向后遍历。
-
这是直观上的比较
2. 最长相等前后缀:顾名思义就是一段长串中前后相同长度的部分是完全一样的,比如"aba",这一段最长相等前后缀就是a,它的长度为一,我们注意到上述图示中,第一次字符不匹配时的主串为“abccab”(我截取前一部分),它的最长相等前后缀为"ab",长度为2,我们注意到字串便是回溯到了这个位置。
所以我们要做的就是求出每一个字符的最长相等前后缀,并将他保留到数组,记作next数组,我们定义它表示next[i]这个位置前的最长相等前后缀长度,比如"ab",那么next[1]=0。
3.求next数组
此为图示:
char s[N]; int next[N]; void getnext(char s[]){ int i=0,j=-1,len=strlen(s); next[0]=-1;//第一个字符没有最长相等前后缀所以赋值-1 while(i<len-1){//注意到下方i++,所以i还是会到len-1 if(j==-1||s[i]==s[j]) i++,j++,next[i]=j;//保留最长相等前后缀 else j=next[j];//重新匹配最长相等前后缀 } }
4.KMP
char s[N],t[N];//t是子串 int kmp(char s[]){ getnext(s); int len1=strlen(s),i=0,j=0,d=0; int len2=strlen(t); while(i<len1&&j<len2){ if(j==-1||s[i]==t[j]) i++,j++;//相同继续匹配 else j=next[j];//不同回溯字串 } if(j==len2) reutrn i-len2;//返回下标 else return -1;//未找到 return d; }
5.不过kmp算法仍有可改进之处,那便是next数组,比如对于"aaabaaassssss","aaacbbb",当比较到第四个时,字串回溯为2,仍然是a,这就有待改进,我们可以优化next保存的值,尽可能跳过这种多余比较。
void getnext(char s[]){ int i=0,j=-1,len=strlen(s);
next[0]=-1; while(i<len-1){ if(j==-1||s[i]==s[j]){ i++,j++; if(s[i]!=s[j]) next[i]=j;//这等于原来的next[i]=j,代表着字串返回后相同,保存长度 else next[i]=next[j];//不同的的话就保存就再回溯一次的长度 }//为什么你不写一个直接保留最终位置的next呢?(我也不会,这还是看的别人代码。。。) else j=next[j]; } }
6.算法复杂度,假设主串长度n,字串为m,朴素做法最好情况为O(n),最坏为O(n*m);
kmp,假设主串长度n,字串为m,求next数组的时间复杂度为O(m),总时间复杂度为O(m+n)(我不会,不好意思,网上的太长了,也许以后会看看再补上)
标签:主串,int,next,学习,后缀,算法,kmp 来源: https://www.cnblogs.com/-Icarus/p/15890412.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。