再来一个fft字符串匹配 Fuzzy Search

#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cmath>

using namespace std;
const double pi = acos(-1.0);
const int maxn = 1e6 + 10;
int sum[maxn];
int can[maxn][10];
int num[maxn];
char s[maxn], p[maxn];
int pre[maxn], nex[maxn];

struct cp
{
    double r, i;
    cp(double _r = 0, double _i = 0)
    {
        r = _r;
        i = _i;
    }
    cp operator +(const cp &p) const
    {
        return cp(r + p.r, i + p.i);
    }
    cp operator -(const cp &p) const
    {
        return cp(r - p.r, i - p.i);
    }
    cp operator *(const cp &p) const
    {
        return cp(r * p.r - i * p.i, r * p.i + i * p.r);
    }
};
cp a[maxn], b[maxn];
int get(char c)
{
    if(c == 'A')
        return 0;
    else if(c == 'C')
        return 1;
    else if(c == 'G')
        return 2;
    else
        return 3;
}

void change(cp y[], int len)
{
    for(int i = 1, j = len / 2; i < len - 1; ++i)
    {
        if(i < j) swap(y[i], y[j]);
        int k = len / 2;
        while(j >= k)
        {
            j -= k;
            k>>=1;
        }
        if(j < k)
            j += k;
    }
}

void fft(cp y[], int len, int op)
{
    change(y, len);
    for(int h = 2; h <= len; h<<=1)
    {
        cp wn(cos(-op * 2 * pi / h), sin(-op * 2 * pi / h));
        for(int j = 0; j < len; j += h)
        {
            cp w(1, 0);
            for(int k = j; k < j + h / 2; k++)
            {
                cp u = y[k];
                cp t =w * y[k + h / 2];
                y[k] = u + t;
                y[k + h / 2] = u - t;
                w = w * wn;
             }
        }
    }
    if(op == -1)
    {
        for(int i = 0; i < len; i++)
        {
            y[i].r /= len;
        }
    }
}
void conv(int n, int m, int len, int x)
{
    for(int i = 0; i < n; i++)
    {
        a[i] = cp(can[i][x], 0);
    }
    for(int i = n; i < len; i++)
    {
        a[i] = cp(0, 0);
    }
    for(int i = 0; i < m; i++)
    {
        if(get(p[i]) == x) b[i] = cp(1, 0);
        else b[i] = cp(0, 0);
    }
    for(int i = m; i < len; i++)
    {
        b[i] = cp(0, 0);
    }
    fft(a, len, 1);
    fft(b, len, 1);
    for(int i = 0; i < len; i++)
        a[i] = a[i] * b[i];
    fft(a, len, -1);
    for(int i = 0; i < len; i++)
        sum[i] += (int)(a[i].r + 0.5);
}

int main()
{
    int n, m, k;
    scanf("%d%d%d%s%s", &n, &m, &k, s, p);
    int len = 1;
    while(len < n * 2 || len < m * 2)
        len<<= 1;
    memset(pre, -1, sizeof(pre));
    memset(nex, -1, sizeof(nex));
    memset(can, 0, sizeof(can));
    memset(sum, 0, sizeof(sum));
    for(int i = 0; i < n; i++)
    {
        num[i] = get(s[i]);
        int x = num[i];
        can[i][x]= 1;
        for(int j = 0; j < 4; j++)
        {
            if(~pre[j] && i - pre[j] <= k) can[i][j] = 1;
        }
        pre[x] = i;
    }
    for(int i =  n - 1; i >= 0; --i)
    {
        int x =  num[i];
        for(int j = 0; j < 4; ++j)
        {
            if(~nex[j] && nex[j] - i <= k) can[i][j] = 1;
        }
        nex[x] = i;
    }
    reverse(p, p + m);
    for(int i = 0; i < 4; ++i)
    {
        conv(n, m, len, i);
    }
    int ans = 0;
    for(int i = 0; i < n + m - 1; i++)
    {
        if(sum[i] == m)
            ans++;
    }
    printf("%d\n", ans);
    return 0;
}

发布了40 篇原创文章 · 获赞 13 · 访问量 853

猜你喜欢

转载自blog.csdn.net/weixin_43891021/article/details/102575064