一、概念:
(1)最长前后缀公共子串:
字符串的一个前缀和一个后缀,如果它们相同,就被称为一个前后缀公共子串。特别地,我们定义最长前后缀公共子串不能是字符串本身。
eg:abcdabc->abc
aaaaaaa->aaaaaa
(2)字符串匹配:
模式匹配:子串的定位操作通常称为串的模式匹配。
目标串:主串S
模式串:子串P
匹配成功:若存在P的每个字符依次和S中的一个连续字符序列相等,则称匹配成功。返回P中第一个字符在S中的位置。
匹配不成功:返回-1。
二、字符串匹配:
1、朴素的字符串匹配:
如果当前字符匹配成功(即S[i]==P[j]),则i++,j++,继续匹配下一个字符。
如果失配(即S[i]!=P[j]),令i=i-(j-1),j=0。
相当于每次匹配失败后,我们让P在S中的起点变成下一个位置,然后重新进行匹配。
2、KMP算法:O(n+m)
利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。
核心思想:每次匹配过程中出现字符比较不等时,不回溯主指针i,利用已得到的部分匹配结果将模式串向右滑动尽可能近的一段距离,继续进行比较。
next:
定义失配函数next(j),表示当模式串中第j个字符与主串s[i]失配时,在模式串中可能和主串中s[i]匹配的字符的位置。
next数组和最长公共前后缀的关系:s[0…next[i]-1]与s[i-next[i]…i-1]是相同的。例如next[j]=k,代表s[0…k-1]与s[i-k…i-1]是完全一致的。所以可以认为next[i]表示了字符串s[0…i-1]的相同的前后缀的长度。next[0]=-1。
算法流程:
如果j=-1或者当前字符匹配成功(s[i]==p[j]),都令i++,j++。
如果j!=-1且当前字符匹配失败(s[i]!=p[j]),则令i不变,j=next[j]。意味着失配时,p相对于s向右移动了j-next[j]位。
即模式串向右移动的位数为:失配字符所在位置-失配字符对应的next值,即移动的实际位数为:j-next[j],且此值大于等于1。
求next:
假设当前next数组中0~i-1个元素均已求出,现在求ne