FFT字符串匹配

定义字符串下标从000,开始,有文本串AAA长度为nnn,模式串BBB长度为mmm,我们可以考虑一个函数f(x,y)=A(x)−B(y)f(x, y) = A(x) - B(y)f(x,y)=A(x)−B(y)。

我们设F(x)(x≥m−1)=∑i=0m−1f(x−m+1+i,i)F(x)(x \ge m - 1) = \sum\limits_{i = 0} ^{m - 1} f(x - m + 1 + i, i)F(x)(x≥m−1)=i=0∑m−1​f(x−m+1+i,i),由定义显然可以得到如果F(x)=0F(x) = 0F(x)=0,则A[x−m+1,x]=BA[x - m + 1, x] = BA[x−m+1,x]=B也就是两个字符匹配上了,

但是考虑"ab","ba""ab", "ba""ab","ba"两个字符串,他们也是匹配的,我们稍微修改一下f(x,y)f(x, y)f(x,y)函数令其为:(A(x)−B(y))2(A(x) - B(y)) ^ 2(A(x)−B(y))2,这样这个函数就没有问题了。

我们考虑翻转一下BBB串,令其为SSS,则有B(i)=S(m−i−1)B(i) = S(m - i - 1)B(i)=S(m−i−1),
F(x)=∑i=0m−1(A(x−m+1+i)−S(m−i−1))2F(x)=∑i=0m−1S(m−i−1)2+∑i=0m−1A(x−m+1+i)2−2×∑i=0m−1A(x−m+1+i)S(m−i−1)F(x) = \sum\limits_{i = 0} ^{m - 1} \left(A(x - m + 1 + i) - S(m - i - 1)\right) ^ 2\\ F(x) = \sum_{i = 0} ^{m - 1} S(m - i - 1) ^ 2 + \sum_{i = 0} ^{m - 1} A(x - m + 1 + i) ^ 2 - 2 \times \sum_{i = 0} ^{m - 1} A(x - m + 1 + i) S(m - i - 1)\\ F(x)=i=0∑m−1​(A(x−m+1+i)−S(m−i−1))2F(x)=i=0∑m−1​S(m−i−1)2+i=0∑m−1​A(x−m+1+i)2−2×i=0∑m−1​A(x−m+1+i)S(m−i−1)
第一项是一个定值,第二可以O(n)O(n)O(n)预处理,然后前缀和O(1)O(1)O(1)得到,第三项不难发现是一个卷积的形式,所以可以通过FFTFFTFFT得到,整体复杂度O(nlog⁡n)O(n \log n)O(nlogn)。

以上我们已经可以解决当模式串的字符串匹配了,尽管复杂度不如KMPKMPKMP优秀,但是我们考虑一个缺项字符串匹配:

a*b

aebr*ob

我们考虑重新设计f(x,y)f(x, y)f(x,y)函数,定义f(x,y)=(A(x)−B(y))2A(x)B(y)f(x, y) = (A(x) - B(y)) ^ 2 A(x) B(y)f(x,y)=(A(x)−B(y))2A(x)B(y),同样的考虑翻转BBB串,有B(i)=S(m−1−i)B(i) = S(m - 1 - i)B(i)=S(m−1−i)。
F(x)=∑i=0m−1(A(x−m+1+i)−S(m−1−i))2A(x−m+1+i)S(m−1−i)∑i=0m−1A(x−m+1+i)S(m−1−i)3+∑i=0m−1A(x−m+1+i)3S(m−1−i)−2×∑i=0m−1A(x−m+1+i)2S(m−1−i)2F(x) = \sum_{i = 0} ^{m - 1} (A(x - m + 1 + i) - S(m - 1 - i)) ^ 2 A(x - m + 1 + i) S(m - 1 - i)\\ \sum_{i = 0} ^{m - 1}A(x - m + 1 + i) S(m - 1 - i) ^ 3 + \sum_{i = 0} ^{m - 1} A(x - m + 1 + i) ^ 3 S(m - 1 - i) - 2 \times \sum_{i = 0} ^{m - 1} A(x - m + 1 + i) ^ 2 S(m - 1 - i) ^ 2\\ F(x)=i=0∑m−1​(A(x−m+1+i)−S(m−1−i))2A(x−m+1+i)S(m−1−i)i=0∑m−1​A(x−m+1+i)S(m−1−i)3+i=0∑m−1​A(x−m+1+i)3S(m−1−i)−2×i=0∑m−1​A(x−m+1+i)2S(m−1−i)2
容易发现这里是三个多项式相加的形式,所以只要做三次FFTFFTFFT即可得到答案,放一个模板题。

#include <bits/stdc++.h>using namespace std;struct Complex {double r, i;Complex(double _r = 0, double _i = 0) : r(_r), i(_i) {}
};Complex operator + (const Complex &a, const Complex &b) {return Complex(a.r + b.r, a.i + b.i);
}Complex operator - (const Complex &a, const Complex &b) {return Complex(a.r - b.r, a.i - b.i);
}Complex operator * (const Complex &a, const Complex &b) {return Complex(a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r);
}Complex operator / (const Complex &a, const Complex &b) {return Complex((a.r * b.r + a.i * b.i) / (b.r * b.r + b.i * b.i), (a.i * b.r - a.r * b.i) / (b.r * b.r + b.i * b.i));
}Complex operator * (const Complex &a, const double &b) {return Complex(a.r * b, a.i * b);
}const int N = 2e6 + 10;int r[N];void get_r(int lim) {for (int i = 0; i < lim; i++) {r[i] = (i & 1) * (lim >> 1) + (r[i >> 1] >> 1);}
}void FFT(Complex *f, int lim, int rev) {for (int i = 0; i < lim; i++) {if (i < r[i]) {swap(f[i], f[r[i]]);}}const double pi = acos(-1.0);for (int mid = 1; mid < lim; mid <<= 1) {Complex wn = Complex(cos(pi / mid), rev * sin(pi / mid));for (int len = mid << 1, cur = 0; cur < lim; cur += len) {Complex w = Complex(1, 0);for (int k = 0; k < mid; k++, w = w * wn) {Complex x = f[cur + k], y = w * f[cur + mid + k];f[cur + k] = x + y, f[cur + mid + k] = x - y;}}}if (rev == -1) {for (int i = 0; i < lim; i++) {f[i].r /= lim;}}
}// const int N = 1e6 + 10;Complex a[N], b[N], c[N];char str1[N], str2[N];int A[N], S[N], n, m, lim;int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);scanf("%d %d %s %s", &m, &n, str2, str1);for (int i = 0; i < n; i++) {A[i] = str1[i] == '*' ? 0 : str1[i] - 'a' + 1;}for (int i = 0; i < m; i++) {S[i] = str2[m - i - 1] == '*' ? 0 : str2[m - i - 1] - 'a' + 1;}lim = 1;while (lim < n + m) {lim <<= 1;}get_r(lim);for (int i = 0; i < lim; i++) {b[i] = Complex(A[i], 0);c[i] = Complex(S[i] * S[i] * S[i], 0);}FFT(b, lim, 1), FFT(c, lim, 1);for (int i = 0; i < lim; i++) {a[i] = a[i] + b[i] * c[i];}for (int i = 0; i < lim; i++) {b[i] = Complex(A[i] * A[i] * A[i], 0);c[i] = Complex(S[i], 0);}FFT(b, lim, 1), FFT(c, lim, 1);for (int i = 0; i < lim; i++) {a[i] = a[i] + b[i] * c[i];}for (int i = 0; i < lim; i++) {b[i] = Complex(A[i] * A[i], 0);c[i] = Complex(S[i] * S[i], 0);}FFT(b, lim, 1), FFT(c, lim, 1);for (int i = 0; i < lim; i++) {a[i] = a[i] - 2 * b[i] * c[i];}FFT(a, lim, -1);vector<int> ans;for (int i = m - 1; i < n; i++) {if ((long long)(a[i].r + 0.5) == 0) {ans.push_back(i - m + 2);}}printf("%d\n", ans.size());for (auto it : ans) {printf("%d ", it);}puts("");return 0;
}

FFT字符串匹配(解决通配符问题)相关推荐

  1. 2018 ACM-ICPC 中国大学生程序设计竞赛线上赛 H题 Rock Paper Scissors Lizard Spock.(FFT字符串匹配)...

    2018 ACM-ICPC 中国大学生程序设计竞赛线上赛:https://www.jisuanke.com/contest/1227 题目链接:https://nanti.jisuanke.com/t ...

  2. HDU 6975 Forgiving Matching 快速傅里叶变换处理带通配符字符串匹配

    文章目录 题意 题解 众所周知多校签到题中必有一道板子题,那么只要会使用板子就可以多做出一道签到了. 本题就是一道FFT的板子题. 题意 给出长度为nnn的字符串sss,长度为mmm的字符串ttt,定 ...

  3. 程序员编程艺术第三十 三十一章 字符串转换成整数,通配符字符串匹配

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 第三十~ ...

  4. 字符串转换成整数,带通配符的字符串匹配

    之前本一直想写写神经网络算法和EM算法,但写这两个算法实在需要大段大段的时间,而平时上班,周末则跑去北大教室自习看书(顺便以时间为序,说下过去半年看过的自觉还不错的数学史方面的书:<数理统计学简 ...

  5. 程序员编程艺术第三十~三十一章:字符串转换成整数,通配符字符串匹配

    第三十~三十一章:字符串转换成整数,带通配符的字符串匹配 前言 之前本一直想写写神经网络算法和EM算法,但写这两个算法实在需要大段大段的时间,而平时上班,周末则跑去北大教室自习看书(顺便以时间为序,说 ...

  6. 字符串转换成整数,通配符的字符串匹配问题

    http://blog.csdn.net/v_july_v/article/details/9024123#comments 前言 之前本一直想写写神经网络算法和EM算法,但写这两个算法实在需要大段大 ...

  7. 2021年度训练联盟热身训练赛第四场 H - Rock Paper Scissors(字符串匹配,FFT)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 2021年度训练联盟热身训练赛第四场 H - Rock Paper Scissors(字符串匹配,FF ...

  8. 一招解决4道leetcode hard题,动态规划在字符串匹配问题中的应用

    全文共2869个字,6张图,预计阅读时间15分钟. 在做leetcode的时候,遇到hard题大家往往都觉得头疼,但其实,掌握方法,举一反三,hard题有时候我们也能想到好的思路,顺利攻破,今天我们就 ...

  9. 【C#】KPM算法解决字符串匹配问题

    KPM算法解决字符串匹配问题 什么是KPM算法 步骤 Ⅰ根据<最大长度表>部分匹配表(next) 寻找最长前缀后缀 Ⅱ 根据 部分匹配表 进行匹配 代码实现 什么是KPM算法   Knut ...

最新文章

  1. SpringBoot多线程环境下,解决多个定时器冲突问题
  2. nature | 基于深度学习方法的虚拟组织染色
  3. go语言笔记——go是有虚拟机runtime的,不然谁来做GC呢,总不会让用户自己来new和delete进行内存管理吧,还有反射!Go 的 runtime 嵌入到了每一个可执行文件当中...
  4. json里面返回模板输出的html,在JSON响应中返回完整页面的HTML而不是字符串输出...
  5. php7 mcrypt windows,Windows下php安装mcrypt扩展问题
  6. 容器编排技术 -- Kubernetes Pod 生命周期
  7. 用代码理解ObjC中的发送消息和消息转发
  8. 局域网服务器时间自动校准,实现局域网内服务器时间同步的方法
  9. 小米4进入开发者模式
  10. jordan标准 相似_Jordan 标准型定理
  11. 大学生体育运动网页设计模板代码 DIV布局校园运动网页作业成品 HTML学校网页制作模板 学生简单体育运动网站设计成品
  12. 国产首发:上海川土微电子数字接口电源数字隔离芯片模拟芯片领导者
  13. 第12章实验1:学生成绩管理系统V5.0
  14. uniapp打包 云端服务器返回错误:请先完成企业实名认证,证明您是“****“的开发者。如有疑问,请发邮件到service@dcloud.io咨询
  15. TensorRT详细入门指南
  16. 淘宝淘口令解密,解析,转换接口,API对接
  17. 《Excel 数据之美--科学图表与商业图表的绘制》
  18. insmod: error inserting 'memdev.ko': -1 File exists
  19. PaaS architecture
  20. 一个APP想法,如何做到从想法到上线的全过程操作

热门文章

  1. python包实际怎么使用_Python--模块与包
  2. 利用for循环调用插入方法批量插入 一条失败_算法与数据结构(1):基础部分——以插入排序为例...
  3. python 新建html_Python学习第226课——html中创建按钮
  4. 当代年轻人,都有些不成文的规定?
  5. Python为什么是编程语言中最skr的?
  6. 【干货】人人都能看懂的LSTM
  7. android什么是回调,Android中的回调是什么?
  8. mysql环境搭载后老出错_使用Docker在window10下搭建SWOFT开发环境,mysql连接错误
  9. ajax jquery php_基于Ajax jquery的使用php登录
  10. java string底层实现_Java-学习日记(Shell与String底层原理)