利用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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM