Fine-Grained学习笔记(1):卷积,FFT与花式字符串匹配

Fine-Grained,在算法复杂度理论中特指,对各类算法的复杂度,进行(相较于P与NP的粗粒度分类的)细粒度分类,例如,证明某问题存在 n2/logn 的算法.Fine-Grained是一个新兴领域,其研究前景可看作是计算机科学学科中的石墨烯与钙钛矿(误).

本系列主要参考University of Illinois at Urbana-Champaign的Timothy M. Chan在2022年秋季的课程,该课程的课堂笔记是公开的:CS 598 TMC, Fall 2022 (illinois.edu)

问题:卷积

给定长度为 n 的序列 A=<a0,a1,,an1>,B=<b0,b1,,bn1>,计算序列C=<c0,c1,,cn1>,其中ci=Σk=0iakbik

等价问题:

给定两个多项式

A(x)=an1xn1+an2xn2++a0

B(x)=bn1xn1+bn2xn2++b0

计算C(x)=A(x)B(x)=c2n2x2n2++c0

朴素的算法:暴力,复杂度为O(n2)

有无更好的办法?

Karatsuba算法(1960)

热身:

n=2时,已知a0,a1,b0,b1,计算

c0=a0b0

c1=a1b0+a0b1

c2=a1b1

这种方法需要4做4次乘法,但如果考虑

c1=(a1+a0)(b1+b0)a0b0a1b1

便只需要做三次乘法.

那么对于任意n,使用分治法,将A(x),B(x)写成如下形式:

A(x)=A1(x)xn/2+A0(x)

B(x)=B1(x)xn/2+B0(x)

A(x)B(x)=A1(x)B1(x)xn+(A1(x)B0(x)+A0(x)B1(x))xn/2+A0(x)B0(x)

T(n)为以该算法进行卷积运算的复杂度

T(n)=3T(n/2)+O(n)

T(n)=O(nlog23)O(n1.59)

Toom&Cook算法(1963)

热身:考虑n=3的情况

给定a0,a1,a2,b0,b1,b2,计算

c0=a0b0

c1=a0b1+a1b0

c2=a0b2+a1b1+a2b0

c3=a1b2

c4=a2b2

共计需要9次乘法

更优的方法:令

d0=a0b0

d1=(a2+a1+a0)(b2+b1+b0)

d2=(4a2+2a1+a0)(4b2+2b1+b0)

d3=(9a2+3a1+a0)(9b2+3b1+b0)

d4=(16a2+4a1+a0)(16b2+4b1+b0)

实际上,若令dk=(k2a2+ka1+a0)(k2b2+kb1+b0)

dk=c4k4+c3k3+c2k2+c1k+c0(k=0,4)

以高斯消元即可求得c0,,c4,该方法仅需5次乘法即可求解n=3的卷积

对于任意的n,利用上述方法进行三路分治,记运行时间为T(n)

T(n)=5T(n/3)+O(n)

T(n)=O(nlog35)O(n1.41)

推广的分治法

总结上述两个算法,可以得到规律:规模为r的卷积求解问题,可以仅用(2r1)次乘法求解.那么考虑对于规模为n的问题,对其进行r路分治求解,记其时间复杂度为T(n)

T(n)=(2r1)T(n/r)+O(n)

T(n)=O(nlogr(2r1))

O(nlog(2r)logr)

O(n1+1logr)

O(n1+ϵ)

Cooley&Tukey 算法(快速傅立叶变换,FFT)

博主注:FFT虽然能够将卷积的复杂度降低到O(nlogn),但运算过程中涉及了复变三角函数,必须假定无限精度实数的运算能在O(1)时间内完成,但此假设在计算复杂度领域内常用的RAM模型中并不成立,该算法的存在能否证明卷积运算的复杂度是O(nlogn),此处存疑.

应用:n位大整数乘法

应用:3SUM问题(元素限制为有限整数)

[a,b]={a,a+1,,b},即a,b之间的全体整数

[U]=[0,U],即0,U之间的全体整数.

给定A,B,C[U],|A|,|B|,|C|=O(n),判断是否存在aA,bB,cC,使得a+b=c

朴素算法:

暴力,O(n^3)

尺取法:

稍微好一点,将A,B进行排序,定义两个指针分别指向A中最小值和B中最大值,比目标值小就把指向A的指针往右挪,否则就把指向B的指针往左挪,这样,对于每个cC,只需要做O(n)次操作.总时间复杂度O(n2)

卷积法:

定义函数fa={1aA0aA

gb={1bB0bB

计算hc=Σa=0U1fagca,这一步卷积可以在O(UlogU)时间内解决,当Un2时,该方法较优.

应用:带通配符的字符串匹配

Σ为字母表,给定模式串P=p1pm(Σ{?}),文本串T=t1tn(Σ{?}),(m<n),判断模式串是否出现于文本串中,用符号表示:

i[n],j[m],pj=ti+jpj=?ti+j=?

朴素算法:

暴力,O(mn)

KMP算法:

预处理模式串,寻找每个前缀字符串的后缀字符串,用于在失配发生时,跳过文本串中没必要匹配的部分.复杂度O(n),但不能解决通配符的情况.

将字母表Σ中的所有字母映射到[1:|Σ|]中的数字,以便进行数学运算.将通配符?映射为0

卷积法:

考虑如下的匹配函数序列:

fi=Σj=1m(pjti+j(pjti+j)2)

其意义是,若模式串第j位和文本串第i+j位匹配上(包括存在通配符和两个字符相等),则该单项值为0,否则为正数,若求和为0,则说明文本串从第i位开始和模式串匹配上了.

接下来将该表达式展开

fi=Σj=1m(pj3ti+j)2Σj=1m(pj2ti+j2)+Σj=1m(pjti+j3)

将字符串P反转,记为Q,即qj=pm+1j,表达式可写为如下形式

fi=Σj=1m(qm+1j3ti+j)2Σj=1m(qm+1j2ti+j2)+Σj=1m(qm+1jti+j3)

可以看出是三次卷积.

时间复杂度O(nlogn)

时间复杂度还可以优化到O(nlogm),具体方法是将文本串T按照每块m个元素划分为n/m块,进行n/m次卷乘,每次计算T中的两个块与P的全部.

应用:字符串模糊匹配

定义:字符串的汉明距离

字符串A,BΣn,字符串的汉明距离定义为|{j:ajbj}|,即两个字符串之间有多少个对应位置不相等.

给定模式串P=p1pmΣ,文本串T=t1tnΣ和限制k,判断是否存在i,使得p1pm,ti+1ti+m的汉明距离k

朴素算法:

暴力,O(mn)

算法1:

定义函数序列μi=|{j:pj=ti+j}|,计算这个函数

如何计算这个函数呢?对于所有的cΣ,定义

μi(c)=|{j:pj=ti+j=c}|=Σj[pj=c][ti+j=c]

O(n+m)时间构造出A(c)=<a1(c),,am(c)>,B(c)=<b1(c),,bn(c)>,ak(c)=[pm+1k=c],bk(c)=[tk=c],后,进行卷积即可.

计算完全部μi(c)之后,令μi=ΣcΣμi(c),然后遍历μi,判断其中是否有连续m个元素之和mk.

总时间复杂度O(|Σ|nlogn)

但当|Σ|较大时又该怎么办呢?

Abrahamson算法(1987):

思路:将字母表中元素按出现次数高低进行分类

ΣH={cΣ:c在模式串P中出现次数>Δ}

ΣL={cΣ:c在模式串P中出现次数Δ}

这样便保证了|ΣH|m/Δ

1.高频情况

对于每个cΣH,使用卷积计算μi(c),并令μi=ΣcΣHμi(c),时间复杂度O(|ΣH|nlogn)=O(mΔnlogn)

2.低频情况

对于所有l[1:n],若tlΣL,那么对于所有满足pj=tlj(总数Δ),令μlj加一.时间复杂度为O(Δn)

总运行时间O(mΔnlogn+Δn),令Δ=mlogn,总时间复杂度则为O(nmlogn+nlogn)=O~(nm)

注:O~()指相比O()多出对数级.

Amir-Lewenstein-Porat(2004) O~(nk)

Gawrychowski-Vzanski(2018) O~(n+nkm)

接近于O(n)

应用:子集和问题

对于集合A,记Σ(A)A中所有元素之和.

给定由S个正整数组成的集合S,目标值T,判断是否存在子集RS使得Σ(R)=T

暴力枚举+尺取:

S划分为两个大小为n/2的子集,枚举全部的子集和并归并排序,然后对以此法获得的两个长度为O(2n/2)的有序序列进行尺取,时间复杂度O(2n/2)

DP(动态规划):

时间复杂度O(nT)

一个用于求解可多次选取的子集和问题的思路:

观察:如果S中的元素可多次选取进R中,那么定义

C(j)[i]=真,当且仅当存在多重集合RS,|R|j,Σ(R)=i

那么c(j)[i]可以通过如下公式求出:

C(j)[i]=i=0i(C(j/2)[i]C(j/2)[ii])

这又是一个卷积的形式,以此方法对原问题进行分治,总时间复杂度为O(TlogTlogn)=O~(T)(假定nT,否则集合S中要么存在着比T还大的元素,可以一开始就排除掉,要么存在着重复元素,要么二者兼有)

但此方法对于一般的(不允许重复选取元素的)子集和问题无效

Bringmann算法(2017):

随机化地用于求解一般子集和问题的算法

引理1:

假定待求集合S[U]中存在解RS,且|R|k,则存在一个随机化算法,可在O~(k2U)时间内求得这个解.

证明:

(ab)为组合数,即在a个互不相同的物品中取出b个的方法数.

考虑如下事实:将k个球随机地放进k2个桶中,每个桶中球的个数均1的概率1/2.("存在两个球被放进了同一个桶中"的概率 (k2)1k2=12)

那么,考虑将S随机地划分为k2个子集,S=S1S2Sk2.

对于给定的Sx,,Sy定义CSx,,Sy[i]为真,当且仅当存在着子集A,Σ(A)=i,且j[x:y],|ASj|1.

那么该序列可以通过如下方式求得:

CS1,,Sl[i]=i=0lU(CS1,,Sl/2[i]CSl/2+1,,Sl[ii])

这是一个对长度为O(lU)的序列的卷积.用该卷积对S1,,Sk2进行分治.记求解子集个数为l的问题的复杂度为T(l),对复杂度进行分析:

T(l)=2T(l/2)+O(lUlog(lU))=O((llogl)Ulog(lU))=O~(lU)

代入l=k2,T(k2)=O~(k2U)

注意,该方法能否得出正确结果依赖于对于S=S1S2Sk2的划分,单次出错概率1/2的情况下可通过重复该算法logn次将出错概率降低至1/n.

引理2:

引理1中的算法可优化至O~(kU)

证明:

考虑如下事实:把k个球放进k个桶里,每个桶中球的个数均n个的概率1O(1/n)(证明参照Chernoff限,待查)

随机地将S划分为k个子集,S=S1S2Sk

定义CSx,,Sy[i]为真,当且仅当存在着子集A,Σ(A)=i,且j[x:y],|ASj|logn

该序列可以通过如下方式求得:

CS1,,Sl[i]=i=0lUlogn(CS1,,Sl/2[i]CSl/2+1,,Sl[ii])

这是一个对长度为O(lUlogn)的序列的卷积.

记求解子集个数为l的问题的复杂度为T(l),同样分析其复杂度:

T(1)是在一个子集Sj中,枚举出至多logn个元素所构成的子集和有哪些,这一步可以通过令S=Sj,k=logn并引入引理1中的算法得到,T(1)=O~(U)

T(l)=2T(l/2)+O(lUlognlog(lU))

T(l)=O~(lU)

l=k,T(k)=O~(kU)

由引理1,2推导出的算法:

对于所有的u=1,2,4,,U,以S={aiS:ai[u:2u1]},k=T/u为输入,应用引理2中的算法,概率性地计算出S={aiS:ai[u:2u1]}中的子集和(只保留T的那些),单步时间复杂度为O~(Tu2u)=O~(T)

对于这O(logU)步中计算出的所有子集和进行归并,归并时间为O(logUTlogT)=O~(T)

Jin&Wu算法(2019):

想法:多项式

求解子集和问题等同于求解ΠaS(1+xa)modxT+1,检查xT项的系数.

exp(x)=ex

上式可写成exp(ΣaSln(1+xa))modxT+1

考虑数学分析知识中的泰勒展开:

ln(1+x)=Σi=1(1)iixi

ln(1+xa)=Σi=1T/a(1)iixaimodxT+1

对于每个a,共有O(T/a)项需要求和

总运行时间O(TΣaS1a)=O(TlogT).

但直接计算这个式子的话是会出现分数项的,考虑随机选取质数p,在Zp即模p的数域中进行运算,除法运算使用快速幂和费马小定理求模p的逆元,这样就变为了一个复杂度为O(Tlog2T)的随机化算法.

posted @   Isakovsky  阅读(87)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示