快速傅里叶变换(FFT)学习笔记
有关多项式的一个基础算法,理解起来比较困难。
快速傅里叶变换(\(\text{Fast Fourier Transform,FFT}\))和傅里叶变换(\(\text{Fourier Transform,FT}\))没什么关系,也不是傅里叶发明的。这种算法用于在 \(O(n\log n)\) 时间复杂度内求出两个多项式的卷积(相当于多项式之间相乘)。
前置知识
多项式的表示
\(n\) 项式等价于 \(n-1\) 次项式。(每个次项的系数都不为零)
系数表示法
形如 \(F(x)=\sum\limits^{n-1}_{i=0} a_ix^i\),把一个 \(n-1\) 次项式的每一次项都表示出来。
两个多项式直接相乘时间复杂度为 \(O(n^2)\)。
点值表示法
对于一个 \(n-1\) 次多项式,可以用 \(n\) 个点 \((x_i,y_i=F(x_i)\) 来表示,相当于由 \(n\) 条 \(n\) 次方程组成的方程组 。
当两个表示不同多项式的点 \(x\) 坐标相等,\(y\) 坐标直接相乘。这种情况下相乘时间复杂度为 \(O(n)\)。
两种表示法间的转换
系数表示法 \(\rightarrow\) 点值表示法
对于 \(n-1\) 次项式选取 \(n\) 个点计算对应值来表示。
点值表示法 \(\rightarrow\) 系数表示法
根据每个点列出 \(n-1\) 元方程,通过高斯消元解出方程。
注意在上述及下文的关于多个多项式的计算中,要统一次数,次数低的多项式要在高次上补零。
复数
单位根是在FFT的思想中一项非常重要的部分。
思想
正常多项式的的乘法并没有什么捷径,时间复杂度 \(O(n^2)\)。于是数学家们想到了可以变为使用点值表示法来运算,能将相乘的时间复杂度优化到 \(O(n)\)。
接下来的难点便是如何进行系数表示法与点值表示法之间的转换。这需要用到离散傅里叶变换(\(\text{Discrete Fourier Transform,DFT}\))和离散傅里叶逆变换(\(\text{Inverse Discrete Fourier Transform,IDFT}\))。
请注意接下来的内容中 \(n=2^m\),其中 \(m\in\N\)(\(m\) 是正整数),许多性质需要依靠这个条件才能推出来。
DFT
DFT 是一种将多项式从系数表示法转换为点值表示法的算法。
我们设多项式 \(A(x)=a_0+a_1x+a_2x^2+a_3x^3+\cdots+a_{n-1}x^{n-1}\)。
将其系数及其所对应项按照下标奇偶性分类,则有
设
(注意此处 \(x\) 指数的区别以及此处的 \(n\) 与上个公式是同一个)
可以得到:
此时将 \(x=\omega_n^k(0<k<\frac{n}{2})\) 带入 \(A(x)\),得
同理,将 \(x=\omega_n^{k+\frac{n}{2}}(0<k<\frac{n}{2})\) 带入 \(A(x)\),得
我们发现这个公式与上面那个公式很像,只有一个系数不一样。也就是说,如果我们知道上面那个
公式,那么下面那个公式就能在 \(O(1)\) 的时间内求出来。
发现当 \(k\) 的的取值遍历 \([0,\frac{n}{2}-1]\) 时,\(k+\frac{n}{2}\) 的取值正好遍历了 \([\frac{n}{2},n-1]\)。
也就是说,只需要算出多项式的一半,另一半就能立马算出来,变成了类似于分治的一种思想。
这种思想的时间复杂度为 \(O(n\log n)\)。
IDFT
IDFT 是一种将多项式从点值表示法转换为系数表示法的算法。是 DFT 的逆算法。