给定字符串s和p,寻找字符串p在字符串s中出现的位置,暴力解法以下所示:算法
++i;++j
,继续匹配下一字符。s[i]
与s[j]
匹配失败,令i-=(j-1),j=0
,即i转到上次首次匹配开头字符的下一位置,j从头开始。int brute_match(string s, string p) { int slen = s.size(); int plen = p.size(); int i = 0, j = 0; while (i < slen and j < plen) { if (s[i] == p[j]) { ++i; ++j; } else { i -= (j - 1); j = 0; } } if (j == plen) return i - j; return -1; }
若是有一种算法可以不让i回退,只须要移动j,那么咱们的算法将会大为简化。数组
在kmp算法中,引入了next数组,表示当前字符以前的子字符串中具备多大长度的相同的前缀后缀,请注意,next字符串的内容是和须要匹配的字符串p相关的。code
在brute-force算法的基础上改进的kmp算法以下所示:blog
int kmp_match(string s, string p,const vector<int> &next) { int slen = s.size(); int plen = p.size(); int i = 0, j = 0; while (i < slen and j < plen) { if (j == -1 or s[i] == p[j]) { ++i; ++j; } else { j = next[j]; } } if (j == plen) return i - j; return -1; }
str
len
中每个位置和字符串s
一对应,表示字符串截止到当前位置最长相同前缀后缀的长度。k
表示当前位置及以前的字符串的最长相同前缀后缀的长度。s[k]
表示原字符串s
在最长前缀后缀str
以后紧跟的那个字符。s[i]!=s[k]
,表明字符i
没法进一步与字符j
匹配,最长相同前缀后缀不可能在上一次匹配的基础之上进一步增加。若是以前可以匹配的最长相同前缀后缀长度大于0,咱们不断尝试在上一次的基础之上下降标准,匹配更小长度的最长前缀后缀。k
调整为k=len[k-1]
,缘由稍后详述。s[i]=s[j]
,这表示最长相同前缀与后缀可以在长度为k
的最长相同前缀后缀的基础之上,再增加一个字符,即len[i]=++k
。不然说明当前位置没有相同前缀后缀,记len[i]=0
。只有长度大于1的字符串才有最长前缀与后缀,最长前缀不包括最后一个字符,最长后缀不包括第一个字符。字符串
k=len[k-1]
缘由讲解假设当前k
指向字符串中f
对应的位置,在e
以前咱们匹配到的最长相同前缀后缀为abeab
,咱们发现e
与f
不能匹配,咱们须要下降标准,尝试匹配更短长度的最长前缀后缀,应该匹配多长的呢?string
咱们发现图中下划线部分的字符串str
彻底相同,咱们要找的长度缩减的最长相同前缀后缀长度不能超过str
的长度,并且要保证这一字符串(设为str_new
)知足条件:是相同的前缀后缀。即图中最前面和最后面标记的字符串str_new
必须彻底同样。根据对称性,这等价于在靠后的str
中寻找最长前缀后缀。并且由于k比较的时候,k
实际指向前面str
的末尾下一位置,因此咱们有:k=len[k-1]
。基础
void calculate_length(string s, vector<int> &len) { len.resize(s.length()); len[0] = 0; int k = 0; for (int i = 1; i < s.length(); ++i) { while (s[i] != s[k] and k > 0) { k = len[k - 1]; } if (s[i] == s[k]) { len[i] = ++k; } else { len[i] = 0; } } }
next数组,表示当前字符以前的子字符串中具备多大长度的相同的前缀后缀,也就是说next 数组至关于“最大长度值” 总体向右移动一位,而后初始值赋为-1。im
其示例代码以下所示,由于和求最长前缀后缀的代码相似,故再也不追究。next
void calculate_next(string s,vector<int>&next){ next.resize(s.length()); int len = s.length(); next[0] = -1; int k = -1; int j = 0; while(j<len-1){ if(k == -1 or s[j] ==s[k]){ ++k; ++j; next[j] = k; } else{ k = next[k]; } } }