??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
]]>
]]>
新地址Q?a data-cke-saved- >夜深人静写算法(二十三)- 最短\
KMP法可以?/span>所有数据结构书上都有,上大学的时候也陆陆l箋学过三次Q每ơ学完看似理解了Q?/span>可是q了不到半年?/span>忘记了,或许是因Z码太短,能写出来׃׃了,没有深入ȝ解,D下次再来看的时候感觉很陌生Q一定是q样的?/span>
今天看了matrix67对KMP的解释,很赞Q附上地址Q?/span>http://www.matrix67.com/blog/archives/115
Z让老年的自׃用在q暮的时候再学一遍KMPQ还是决定把一些关键性的东西记录下来Q如果那时候的自己看到自己当年写的q篇W记能有恍然大悟的感觉,那么现在׃是在费旉了?/span>
定义Q?/span>
S[1... n] 目标?nbsp; T[1...m] 模式?/span>
法目的Q?/span>
从目标串S中找C个子串和模式串T完全匚w?/span>
法核心思想Q?/span>
1) 枚Di?到nQ在S[i-j...i-1]和T[1...j]完全匚w的前提下Q判断S[i]是否和T[j+1]相等Q?/span>
a) 如果相等Q说明S[i-j...i]和T[1...j+1]完全匚wQ那么i和j都自?Q?/span>
b) 如果不相{,则需要找C个最大的j' < jQ满S[i-j'...i-1]和T[1...j']完全匚wQ?/span>
2) 当i=n或j=m的时候说明匹配结束,否则重复1)Q?br />
对于j'可以q样理解Q由于前提是S[i-j...i-1]和T[1...j]完全匚wQ如果要扑ֈ一个j'满S[i-j'...i-1]和T[1...j']也完全匹配,那么T[1...j']必定为T[1...j]的后~Q?/span>证明如下Q首先将以下的子串进行编P A = S[i-j...i-1] B = T[1...j] C = S[i-j'...i-1] D = T[1...j']
因ؓA和B完全匚wQC和D完全匚wQ由于C为A的后~Q所以D为B的后~?/span>
当S[i]和T[j+1]不相{的时候需要调整j的|调整完后的j = Next[j](q个Next[j]是之前所说的j')Q需要满?T[1 ... Next[j] ] = = T[ j - Next[j] + 1... j ]Q?q且Next[j]的值最大,比较书面的说法就是Next[j]表示在模式串T中以Wj个元素ؓl尾的最长后~中满_是T的前~的后~的长?/span>?/span>
举个例子QT = "ababaaba"的Next数组?nbsp;[0, 0, 1, 2, 3, 1, 2, 3]?/span>
׃Next数组表示的含义只和自w的性质有关Q所以在没有目标串的情况下同样可以求出Next数组QKMP的精妙之处就在于求这个Next数组了?/span>
在上文中提到的S和T的匹配中Q每ơS[i-j...i-1]都是量扑ֈ最大的j使得它和T[1...j]完全匚wQ当然有可能找不到这LjQ此时oj = 0Q即 S[i,i-1]和T[1,0]匚w(q是两个IZQ空串和IZ也可以匹配,hohoho~~所以j是一定存在的)。如果现在把S换成TQ那么问题就转化成了T[i-j...i-1]和T[1...j]的匹配问题了Q如果T[i-j...i-1]和T[1...j]完全匚wQƈ且T[1...j]是和T[i-j...i-1]匚w的最长的Ԍ那么 Next[i-1] 是 jQ思考一下红色字的定义就明白了)Q于是问题就转化成了T的自我匹配的q程了?br /> 法复杂度:
O(n+m)
Next函数的求解非常简z:
PKU 3461 Oulipo
题意Q求一个匹配串T在目标串S中的出现ơ数?/span>
题解Q?/span>求出T?/span>Next数组Q然后和Sq行KMP匚wQ匹配时当j = =m的时候表C找C个可行解Q计数器+1Q然后将Next[j]赋值给jQ得它的最长前~能够l箋和目标串q行匚w?/span>
KMP匚wq程和Next数组的求解是一L?/span>
HDU 4763 Theme Section
题意Q给定一个长度ؓN(1 <= N <= 106)的字W串SQ问能否和模式串EAEBEq行匚w其中A和B表示L随机字符Q如果能匚wQ输出E的最大可能长度,不能匚w输出0?/span>
题解Q首先利用KMP求出S的Next数组Q那么S[1...Next[N]]、S[1...Next[Next[N]]]、S[1...Next[...[N]] ]必定能和S的后~q行完全匚wQ将q些Next[i]利用一ơP代求出来Q最l的{案一定在q些gQ然后从大到枚举这些|判断可行性?/span>
假设当前枚D长度为iQ那么在S[i+1 ... N-i] 中如果能够找C个长度ؓi的子串满_S[1...i]完全匚wQ那么i是一个可行解Q又因ؓ枚D是从大到进行的Q所以i是E可能的最大长度?/span>
于是问题p{变成了判断S[i+1 ... N-i]中是否存在一个和S[1...i]完全匚w的子丌Ӏ如果存在,那么必定存在一个k( 2*i <= k <= N-i )Q得S[k-i+1 ... k] = = S[1 ... i ]Q所以必定有Next[Next[...[k]]] = = iQ所以我们可以预先将S[i+1 ... N-i]区间内所有的Next值退化后q行HashQ然后在枚D某个长度i的时候去Hash数组中找i是否被标讎ͼ如果被标记说明存在某个k满S[k-i+1 ... k] = = S[1 ... i ]Qi是最大可能长度?/span>
HDU 2594 Simpsons’ Hidden Talents
题意Q给定两个长度不大于50000?/span>Ԍ求两个串的一个最长公共子串满_串ؓW一个串的前~Qƈ且ؓW二个串的后~?/span>
题解Q将两个串用一个从未出现过的字W连接,拼成一个长度ؓN的串Q?/span>然后q行一ơ自我匹配,求出next数组Q根据Next数组的定义,Next[N]是所求的最大长度?/span>
HDU 3746 Cyclic Nacklace
题意Q给定一个长度ؓN(N <= 105)的字W串SQ求在它的末添加几个字W得他变成一个至重复两ơ的q箋重复Ԍ要求d的字W数最?/span>
题解Q首先利用KMPq行一ơ自我匹配求出Next数组Q然后枚N复串的长度iQox = i * (N/i)Q如果x - Next[x] == iQ说明S[x]是S的一个连l重复子Ԍ或者叫q箋重复前缀更加贴切Q,理由很简单,字W串S[x]以长度i为单位分l,
S[1...i] S[i+1...2i] S[2i+1...3i] …… S[(N/i-1)i + 1...(N/i)i]
S[1...i] S[i+1...2i] …… S[(N/i-2)i + 1...(N/i-1)i]
׃x + i = = Next[x]Q可以列{式Q有如下{h关系QS[1...i] = = S[i+1...2i] = = ... = = S[(N/i-1)i + 1...(N/i)i]?/span>
那么剩下的就是要看S[x+1...N]是否为S的前~Q同样可以根据Next数组的定义进行判断,Ҏ的,当x == NӞS[x+1...N] == S[N+1,N]为空Ԍ必定为S的前~Q也是满x件的Q枚举所有满x件的长度LQ取L - (N-x)的最者就是答案了?/span>
PKU 2406 Power Strings
题意Q给定一个长度不过N(N <= 106)的字W串Q它一定是某个串重复Kơ得刎ͼ求这个K的最大倹{?/span>
题解Q假讑֭串T重复Kơ后得到串SQ那么T的长度一定ؓL = N/K(要整?Q则T = S[1...L]Q将S拆分成K份,每䆾长度为LQ则?/span>
S[1...L] = S[L+1...2L] = S[2L+1...3L] = ... = S[(K-1)L+1...KL]
׃要保证K最大,势必L要取最,所以根据Next函数的定义,有Next[KL] = (K-1)L;
即Next[N] = N - LQ所以L = N - Next[N];
但是得出的长度Lq要保证能被N整除Q所以如果不能整除说明L = NQ即K = 1Q而如果能整除Q那么K = N / (N - Next[N]);
PKU 2752 Seek the Name, Seek the Fame
题意Q给定一个长度ؓN(N <= 400000)的字W串Q求它的前缀{于后缀的所有子串的长度?/span>
题解Q考察Next数组的定义。不断P代求N的NextQNext[N]的Next......然后逆序输出卛_?/span>
HDU 3374 String Problem
题意Q给定一个长度ؓN(N <= 106)的字W串SQ然后将它进行左U,d产生N个@环字W串Q求其中字典序最的串的~号以及q样的串的个敎ͼ和字典序最大的串的~号以及q样的串的个数?/span>
题解Q先求字典序最的Q字典序最大的只需要将每个字符?27减去本n再求一ơ字典序最即可;定义两个指针iQjQi初始?Qj初始?Q再定义一个长度变量k = 0Q?/span>
1) 比较S[i+k] 和S[j+k]的大关p:
a) 如果相等Qk自增1Q当k==N则蟩出@环,否则l箋1)的比较;
b) 如果S[i+k] < S[j+k]Qj += k + 1, k = 0;
c) 如果S[i+k] > S[j+k], i += k + 1, k = 0;
2) 如果i 和j相等Qj自增1Q当j==N或i==N则蟩出@环,否则l箋1)的比较;
q样循环l束后如果,取i和j的小者就是答案?/span>
然后在利用求出来的下标,生成一个新的字W串作ؓ匚w串和一个原串的两倍的串作为目标串q行KMP匚wQ得到种数?br />
题意Q给?font face="Times New Roman">N*M(N<=1000, M <= 1000)?/font>01矩阵SQ再l定T(T <= 100)?/font>P*Q(P <= 50, Q <= 50)?/font>01矩阵Q问P*Q的矩阵中有多个?/font>S的子矩阵?/font>
题解Q由?font face="Times New Roman">P <= 50Q所以我们可以把所?/font>P*Q的矩阵进行二q制位压~,?/font>P*Q的矩늚每一列压~成一?/font>64位整敎ͼq样P*Q的矩阵就变成了一个长度ؓQ的整数序?/font>TQ用同样的方式对N*M的矩阵进行压~,d可以产生(N-P+1)个长度ؓM的整数序列,剩下的就是进行最?/font>(N-P+1)?/font>KMP匚w了?/font>