KMP算法初涉
kmp算法
有一个主串s1 和子串s2
暴力求解的方法是:当主**串指针走如图所示的c的位置时,子串指针走到如图所示的d的位置。发现c和d不匹配,此时主指针会退到上一次开始匹配的下一个位置及如图第一个b的位置,这样主串的指针会出现往后回退的情况,极大的浪费的时间。
新的方法:
主指针不在向前回退,让子串向后移动若干位置,然后再按照匹配规则继续匹配,那么应该向后移动多少个位置呢?
如图所示子串应该移动到该位置是最佳的移动方式,那么这个位置是如何判断的呢?
其实就是找出当前字符串中前缀和后缀相同且长度最大的,
子串中在如图所示的子串指针所指的d位置,它前面的字符串是 a b c d a b
这个字符串的前缀有:a ab abc abcd abcda
后缀有:b ab dab cdab bcdab
他们相同的只有ab这个子串 且它的长度是2 ,那么移动的的个数就是 一经匹配成功的数目减去2,即 5-2=3,子串向后移动3个位置就是最佳的选择。如果前面一经匹配好的子串中的前缀和后缀中没有相同的字符串那就更好办了,5-0=5;直接让子串向后移动5个位置;如此一来得到一个关系:子串的每一个字符都对应一个数值,这个数值就是此字符前面的字符串中所有的前缀和后缀相的且长度最大的那个数。
这个数从原理上来说很好求,但是用那种方式最快呢?
不妨把这些数保存到一个数组中命名为next数组
下面就是求next数组的方法:
void getNext() //O(m)复杂度求Next数组
{
int i = 0, j = 0, k = -1;
next[0] = -1;
while(j < m)
{
if(k == -1 || p[k] == p[j]) next[++j] = ++k;
else k = next[k];
}
下面给出字符串的km(数字只需稍作改动)的算法:
int KmpSearch(char* s, char* p)
{
int i = 0;
int j = 0;
int sLen = strlen(s);
int pLen = strlen(p);
while (i < sLen && j < pLen)
{
//①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++
if (j == -1 || s[i] == p[j])
{
i++;
j++;
}
else
{
//②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]
//next[j]即为j所对应的next值
j = next[j];
}
}
if (j == pLen)
return i - j;
else
return -1;
}
以上就是我对kmp的理解,详情请参考牛人详解
梦里不知身是客,一晌贪欢。