kmp算法初步了解
最近一直在看kmp算法来解决字符串匹配的超时问题,看了好多材料终于有一点顿悟了。其实kmp算法难就难在对于next[]数组的理解方面,有很多人不理解不匹配的字符对应的模式函数值next[i]的值是怎么得来的,总结起来解释就是找出不匹配字符前面与开头字符的最大匹配数字。例如在求解模式串T:ababc时其第五个字符前面两个字符与开头两个字符一致,故next[4]=2.除此之外对于其他几种情况有以下总结:
(1)next[0]= -1 意义:任何串的第一个字符的模式值规定为-1。
(2)next[j]= -1 意义:模式串T中下标为j的字符,如果与首字符
相同,且j的前面的1—k个字符与开头的1—k
个字符不等(或者相等但T[k]==T[j])(1≤k<j)。
如:T=”abCabCad” 则 next[6]=-1,因T[3]=T[6]
(3)next[j]=k 意义:模式串T中下标为j的字符,如果j的前面k个
字符与开头的k个字符相等,且T[j] != T[k] (1≤k<j)。
即T[0]T[1]T[2]。。。T[k-1]==
T[j-k]T[j-k+1]T[j-k+2]…T[j-1]
且T[j] != T[k].(1≤k<j);
(4) next[j]=0 意义:除(1)(2)(3)的其他情况。
对于kmp算法而言,第一个难点就是找出模式串的模式函数值,其一般代码抄写如下:
void get_next() { int i = 0, j = -1; next[0] = -1; //赋值字符差串的首个模式函数值为-1; while(i < lenp)//lenp为模式串的长度
{ if(j == -1 || pat[i] == pat[j])//找出模式串中每个字符的模式函数值 { i ++; j ++; next[i] = j; } else j = next[j]; } }
接下来要做的工作是开始于模板串进行匹配,对于匹配的方法,却别于传统可能TLE的代码而言最大的优势就是不用回溯,从而使复杂度降至O(m+n)而不是O(m*n),kmp的关键是在匹配不成功时调用模式函数值,而不是进行回溯到初始位置进行调用。其代码抄写如下:
int KMP() { int i = 0, j = 0; get_next(); while(i < lent && j < lenp)//lent为模版串的长度,其中模版串为text,模式串为pat { if(j == -1 || text[i] == pat[j]) { i ++; j ++; } else j = next[j]; } if(j >= lenp) return i - lenp; else return -1; }
关于 kmp最近只有初步的理解,大多数还是死记硬背的成分,相信写会代码,练习练习也就掌握了。
浙公网安备 33010602011771号