字符串匹配进阶
Posted XINNNNNNNYU
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串匹配进阶相关的知识,希望对你有一定的参考价值。
FFT
A位模式串,长度为n;B为文本串,长度为m。
1.没有通配符的
- 首先引入一个匹配函数 C ( x , y ) = A ( x ) − B ( y ) C(x,y) = A(x) - B(y) C(x,y)=A(x)−B(y),当C(x,y) = 0,我们认为A的第x字符和B的第y个字符相等。
- 再将一个字符匹配扩展到一个字符串。
- 那么,完全匹配函数 P ( x ) = ∑ i = 0 m − 1 C ( i , x − m + i + 1 ) P(x) =\\displaystyle \\sum^m-1_i=0 C(i,x-m+i+1) P(x)=i=0∑m−1C(i,x−m+i+1) ,若P(x) = 0,则B以x结尾的连续m位子串和A完全匹配。
- 上面的完全匹配函数存在一些错误
- 把求和函数拆开会发现就是匹配的两个串的每个字符分别相加,然后;两个和相减。那么只要字符的类型,个数对应相同就被判定相同,忽略了每个字符的对应关系。
- 产生错误的原因是每个字符的匹配函数有正有负,求和可能相互抵消为0。
- 解决方法就是把匹配函数 C ( x , y ) C(x,y) C(x,y)平方,因为若干个平方数相加=0只能是每一项都为0,和我们完全匹配时每个位置的 C ( x , y ) = 0 C(x,y)=0 C(x,y)=0时等价的。
- 等价转化—— 我们把A反转变成S,那么A(i) = S(m-i-1)。因为这样子匹配函数的x,y相加总是等于一个常数。(这很重要)
- 正确的完全匹配函数为 P ( x ) = ∑ i = 0 m − 1 ( S [ m − i − 1 ] − B [ x − m + i + 1 ] ) 2 P(x) =\\displaystyle \\sum^m-1_i=0 (S[m-i-1] - B[x-m+i+1])^2 P(x)=i=0∑m−1(S[m−i−1]−B[x−m+i+1])2
- 将函数暴力展开为 P ( x ) = ∑ i = 0 m − 1 ( S [ m − i − 1 ] 2 + B [ x − m + i + 1 ] 2 − 2 S [ m − i − 1 ] B [ x − m + i + 1 ] ) P(x) =\\displaystyle \\sum^m-1_i=0 (S[m-i-1]^2 + B[x-m+i+1]^2 - 2 S[m-i-1] B[x-m+i+1]) P(x)=i=0∑m−1(S[m−i−1]2+B[x−m+i+1]2−2S[m−i−1]B[x−m+i+1])
- 再展开为三部分
- ∑ i = 0 m − 1 S [ m − i − 1 ] 2 \\displaystyle \\sum^m-1_i=0 S[m-i-1]^2 i=0∑m−1S[m−i−1]2 显然,这是个定值记作T,我们可以 O ( m ) O(m) O(m)暴力预处理
- ∑ i = 0 m − 1 B [ x − m + i + 1 ] 2 \\displaystyle \\sum^m-1_i=0B[x-m+i+1]^2 i=0∑m−1B[x−m+i+1]2 这是一个长度为m的区间和,我们通过预处理前缀和数组f ( x ),然后 O ( 1 ) O(1) O(1)得到
-
−
2
∑
i
=
0
m
−
1
S
[
m
−
i
−
1
]
B
[
x
−
m
+
i
+
1
]
\\displaystyle -2\\sum^m-1_i=0S[m-i-1] B[x-m+i+1]
−2i=0∑m−1S[m−i−1]B[x−m+i+1] 通过上面我们把A用他的反转S替换后,我们发现(m-i-1)+(x-m+i+1) 恒等于x。那么公式为
−
2
∑
i
+
i
=
x
S
[
i
]
B
[
j
]
\\displaystyle -2\\sum_i+i=xS[i] B[j]
−2i+i=x∑S[i]B[j]。
- 另 g ( x ) = ∑ i + i = x S [ i ] B [ j ] \\displaystyle g(x) = \\sum_i+i=xS[i] B[j] g(x)=i+i=x∑S[i]B[j] ,显然这是个多项式乘法,可以通过FFT求出所有值
- P ( x ) = T + f ( x ) − f ( x − m ) − 2 g ( x ) P(x) = T + f(x) - f(x-m) -2g(x) P(x)=T+f(x)−f(x−m)−2g(x) ,每个函数都可以通过上述求出,再 O ( n ) O(n) O(n)求出所有P(x)
-
调整匹配函数——和上述没有通配符的相同,但是我们要去掉通配符位置的贡献。
-
将原字符串是通配符的值设为0,再修改完全匹配匹配函数为 P ( x ) = ∑ i = 0 m − 1 ( S [ m − i − 1 ] − B [ x − m + i + 1 ] ) 2 S [ m − i − 1 ] B [ x − m + i + 1 ] P(x) =\\displaystyle \\sum^m-1_i=0 (S[m-i-1] - B[x-m+i+1])^2S[m-i-1]B[x-m+i+1] P(x)=i=0∑m−1(S[m−i−1]−B[x−m+i+1])2S[m−i−1]B[x−m+i+1]
其中一个为通配符就会乘上0,最后贡献为0
-
暴力展开-> P ( x ) = ∑ i = 0 m − 1 ( S [ m − i − 1 ] 3 B [ x − m + i + 1 ] + B [ x − m + i + 1 ] 3 S [ m − i − 1 ] − 2 ( S [ m − i − 1 ] B [ x − m + i + 1 ] ) 2 ) P(x) =\\displaystyle \\sum^m-1_i=0 (S[m-i-1]^3B[x-m+i+1] + B[x-m+i+1]^3S[m-i-1] - 2 (S[m-i-1] B[x-m+i+1])^2) P(x)=i=0∑m−1(S[m−i−1]3B[x−m+i+1]+B[x−m+i+1]3S[m−i−1]−2(S[m−i−1]B[xUva 11468 改良版AC自动机