균등하게 간격을 둔 3 개의 것을 찾는 것에 관한 최근 퍼즐 블로그 게시물 은 O (n lg n) 시간에 그것을한다고 주장하는 최고의 대답과 함께 stackoverflow 질문 으로 이어집니다. 흥미로운 부분은 솔루션이 다항식을 제곱하고, O (n lg n) 시간에 수행하는 방법을 설명하는 논문을 참조 한다는 점 입니다.
이제 다항식을 곱하는 것은 실제로 곱하는 숫자와 같습니다. 유일한 차이점은 운반이 없다는 것입니다. 그러나 ... 운반은 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)에 숫자를 곱하는 것은 컴퓨터 과학에서 거대한 열린 문제이며, 나는 대답이 이처럼 간단하다고 정말로 의심합니다.
- 운반이 잘못되었거나 O (n lg n)가 아닌가? 나는 값 당 lg n + 1 비트가 캐리를 추적하기에 충분하다는 것을 알아 냈습니다. 알고리즘은 너무 간단하여 잘못되면 놀랐습니다. 개별 증분에 O (lg n) 시간이 걸릴 수 있지만 x 증분에 대한 총 비용은 O (x)입니다.
- 논문의 다항식 곱셈 알고리즘이 잘못되었거나 위반하는 조건이 있습니까? 이 논문은 숫자 이론적 변환 대신 빠른 푸리에 변환을 사용하는데 이는 문제가 될 수 있습니다.
- 많은 똑똑한 사람들 이 40 년 동안 Schönhage-Strassen 알고리즘 의 명백한 변형을 놓쳤 습니까? 이것은 아마도 가장 적은 것 같습니다.
효율적인 다항식 곱셈을 제외하고 실제로 이것을 구현하는 코드를 작성했습니다 (수 이론 정리는 아직 충분히 이해하지 못합니다). 무작위 테스트는 알고리즘이 올바른지 확인하는 것으로 보이므로 시간 복잡성 분석에 문제가있을 수 있습니다.
나는 손으로 모범을 보였다. 나는 산술 실수를했다. 죄송합니다. 실제로 알고리즘을 구현하고 테스트하여 올바른 결과를 얻었습니다.
—
Craig Gidney
x^10 + 2x^8
됩니까? x ^ 10 한 번만 (x ^ 5 * x ^ 5), x ^ 8을 두 번 (x ^ 6 * x ^ 2 + x ^ 2 * x ^ 6)