FFT在字符串匹配中的应用

对于一类字符串匹配问题:

给定长度分别为 \(m,n\) 的字符串 \(A,B\),给出两个相同长度的字符串匹配的定义,要求找出 \(A\)\(B\) 中所有匹配的位置。

可能能用如下方式解决:

定义匹配函数 \(C(a,b)\),使得完全匹配函数 \(P(i)=\sum_{j=0}^{m-1}C(A_j,B_{i+j})\) 等于 \(0\) 当且仅当 \(A\)\(B[i..i+m-1]\) 匹配。

然后,我们将 \(C(a,b)\) 拆成若干个有关 \(a,b\) 的乘积,即 \(C(a,b)=\sum_{k=1}^K f_k(a)g_k(b)\)。然后我们对每个 \(k\) 计算它对 \(P(i)\) 的贡献,即计算 \(P_k(i)=\sum_{j=0}^{m-1}f_k(A_j)g_k(B_{i+j})\)。这是减法卷积,可以优化至 \(O(n\log n)\)

总时间复杂度 \(O(Kn\log n)\),一般来说 \(K\) 是常数。

举几个例子吧:

  • 一般的字符串匹配问题。

    一个想法是设 \(C(a,b)=a-b\),但这只对单个字符生效,对 \(P(i)\) 是不一定生效的,比如 \(\texttt{"ab"}\)\(\texttt{"ba"}\)

    正确的做法应该是设 \(C(a,b)=(a-b)^2\),这样两个字符串一旦出现某个位置不同,\(P(i)\) 就一定大于 \(0\)

  • 带通配符 \(\texttt{\#}\) 的字符串匹配问题。

    上一题的扩展,直接设 \(C(a,b)=[a\neq \texttt{\#}][b\neq \texttt{\#}](a-b)^2\) 即可。

posted @ 2022-10-31 08:15  ez_lcw  阅读(36)  评论(0编辑  收藏  举报