最近puzzle blog post关于找到三个均匀间隔的引导我的stackoverflow question带有一个声称在O(n lg n)时间内完成它的最高答案。有趣的是,解决方案涉及平方多项式,引用paper that describes how to do it in O(n lg n) time。
现在,乘法多项式实际上与乘法数相同。唯一真正的区别是缺乏携带。但......承载也可以在O(n lg n)时间内完成。例如:
var value = 100; // = 0b1100100
var inputBitCount = value.BitCount(); // 7 (because 2^7 > 100 >= 2^6)
var n = inputBitCount * 2; // 14
var lgn = n.BitCount(); // 4 (because 2^4 > 14 => 2^3)
var c = lgn + 1; //5; enough space for 2n carries without overflowing
// do apparently O(n log n) polynomial multiplication
var p = ToPolynomialWhereBitsAreCoefficients(value); // x^6 + x^5 + x^2
var p2 = SquarePolynomialInNLogNUsingFFT(p); // x^12 + 2x^11 + 2x^10 + x^8 + 2x^7 + x^4
var s = CoefficientsOfPolynomial(p2); // [0,0,0,0,1,0,0,2,1,0,2,2,1]
// note: s takes O(n lg n) space to store (each value requires at most c-1 bits)
// propagate carries in O(n c) = O(n lg n) time
for (var i = 0; i < n; i++)
for (var j = 1; j < c; j++)
if (s[i].Bit(j))
s[i + j].IncrementInPlace();
// extract bits of result (in little endian order)
var r = new bool[n];
for (var i = 0; i < n; i++)
r[i] = s[i].Bit(0);
// r encodes 0b10011100010000 = 10000
所以我的问题是:这里的错误在哪里?在O(n lg n)中乘以数字是计算机科学中一个巨大的开放性问题,我真的怀疑答案就是这么简单。
我实际上已经编写了代码来实现它,除了有效的多项式乘法(我还不太了解数论变换)。随机测试似乎证实算法是正确的,因此问题很可能在时间复杂度分析中。
答案 0 :(得分:3)
问题是如果n是字RAM或bit-RAM模型下的位数,则{O}(n)(n)(n)(n)(n)(n(n))时间内不能实际执行SquarePolynomialUsingFFT
步骤。在字RAM模型中(即log(n)位字的常用操作具有单位成本),你只需将n个字吹成n个log(n)字,然后你做一个带O的n(n log) 2 (n))时间。在位RAM模型中(位操作具有单位成本),FFT中的每个操作都需要O(log n)时间,因此整个FFT需要O(n log 2 (n))时间。
Schoenhage-Strassen的神奇之处在于巧妙地递归选择了FFT,因此你不会进行进一步的log(n)爆炸,而只会进行log(log(n))爆炸。如果你有k个m字环元素(因此k * m = n),你只需要O(m * k log(k))时间来在该环中进行m FFT。然后你必须计算k ^ 2相关的m字卷积如果你这样做,但那很酷;我们可以FFT(使用较小的环)批量处理所有k个m字环元素,进行乘法运算,然后进行反FFT运算。