利用FFT来进行字符串匹配
给定串A和串B,A由26个小写字母构成,B由?和26个小写字母构成
?可以和任意字符匹配
求A中出现了多少次B
这里可以使用fft做法,定义向量A和向量B
然后求A和rev(B)的卷积结果C
C的第i-len(B)位就可以表示匹配结果
如果C的第i-len(B)位恰好是B中除了?的字符个数,那么就是匹配成功
这样复杂度就是O((n+m)*(logn + logm))
注意要调整eps,当数据很大的时候,误差会比较大
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <complex> using namespace std; const double pi = acos(-1); const int maxn = 111111; typedef complex<double> Complex; const double eps = 1e-8; void DFT(Complex *a, int n, int t) { if(n == 1) return; Complex a0[n>>1], a1[n>>1]; for(int i = 0; i < n; i += 2) a0[i>>1] = a[i], a1[i>>1] = a[i+1]; DFT(a0, n>>1, t); DFT(a1, n>>1, t); Complex wn(cos(2*pi/n), t*sin(2*pi/n)), w(1, 0); for(int i = 0; i < (n>>1); i++, w *= wn) a[i] = a0[i] + w*a1[i], a[i+(n>>1)] = a0[i] - w*a1[i]; } Complex a[maxn], b[maxn]; int n1, n2, nn, c[maxn]; double x; string s1, s2; int main() { freopen("a.txt", "r", stdin); cin>>s1>>s2; n1 = s1.length(); n2 = s2.length(); int N = n2; for(int i = 0; i < n1; i++) x = 2*pi*(s1[i] - 'a')/26, a[i] = Complex(cos(x), sin(x)); for(int i = 0; i < n2; i++) if(s2[i] != '?') x = 2*pi*(s2[i] - 'a')/26, b[i] = Complex(cos(-x), sin(-x)); else b[i] = Complex(0, 0), N--; for(int i = 0; i < n2/2; i++) swap(b[i], b[n2-i-1]); n1--; n2--; nn = 1; while(nn <= n1+n2) nn <<= 1; DFT(a, nn, 1); DFT(b, nn, 1); for(int i = 0; i <= nn; i++) a[i] = a[i]*b[i]; DFT(a, nn, -1); for(int i = 0; i <= n1+n2; i++) c[i] = abs(a[i].imag()) < eps ? (a[i].real()/nn + eps) : 0; int ans = 0; for(int i = n2; i <= n1; i++) if(c[i] == N) ans++; cout<<ans<<endl; return 0; }