这似乎是一个具有适当边界的简单蛮力算法,其求解时间与 n^1.33 成正比,空间与 n 成正比。或者谁能指出我弄错的地方?
考虑 4 个嵌套循环,每个循环从 1 运行到 n 的三次根。使用这些循环,我们可以遍历 4 个值的所有可能组合,并找到形成出租车号码的对。这意味着每个循环所花费的时间与 n 的立方根 或 n^(1/3) 成正比。将此值乘以 4 得到:
(n^(1/3)^4 = n^(4/3) = n^1.33
我用 JavaScript 编写了一个解决方案并对其进行了基准测试,它似乎正在运行。一个警告是结果只是部分排序。
这是我的 JavaScript 代码(它还不是最佳的,可以进一步优化):
function taxicab(n) {
let a = 1, b = 1, c = 1, d = 1,
cubeA = a**3 + b**3,
cubeB = c**3 + d**3,
results = [];
while (cubeA < n) { // loop over a
while (cubeA < n) { // loop over b
// avoid running nested loops if this number is already in results
if (results.indexOf(cubeA) === -1) {
while (cubeB <= cubeA) { // loop over c
while (cubeB <= cubeA) { // loop over d
if (cubeB === cubeA && a!=c && a!=d) { // found a taxicab number!
results.push(cubeA);
}
d++;
cubeB = c**3 + d**3;
} // end loop over d
c++;
d = c;
cubeB = c**3 + d**3;
} // end loop over c
}
b++;
cubeA = a**3 + b**3;
c = d = 1;
cubeB = c**3 + d**3;
} // end loop over d
a++;
b = a;
cubeA = a**3 + b**3;
} // end loop over a
return results;
}
在浏览器控制台中运行 taxicab(1E8) 大约需要 30 秒,结果会产生 485 个数字。十倍小值taxicab(1E7)(1000 万)需要近 1.4 秒并产生 150 个数字。 10^1.33 * 1.4 = 29.9,即n乘以10会导致运行时间增加10^1.33倍。结果数组未排序,但在快速排序后,我们得到了正确的结果,如下所示:
[1729, 4104, 13832, 20683, 32832, 39312, 40033, 46683, 64232, 65728,
110656, 110808, 134379, 149389, 165464, 171288, 195841, 216027, 216125,
262656, 314496, 320264, 327763, 373464, 402597, 439101, 443889, 513000,
513856, 515375, 525824, 558441, 593047, 684019, 704977, 805688, 842751,
885248, 886464, 920673, 955016, 984067, 994688, 1009736, 1016496, 1061424,
1073375, 1075032, 1080891, 1092728, 1195112, 1260441, 1323712, 1331064,
1370304, 1407672, 1533357, 1566728, 1609272, 1728216, 1729000, 1734264,
1774656, 1845649, 2048391, 2101248, 2301299, 2418271, 2515968, 2562112,
2585375, 2622104, 2691451, 2864288, 2987712, 2991816, 3220776, 3242197,
3375001, 3375008, 3511872, 3512808, 3551112, 3587409, 3628233, 3798613,
3813992, 4033503, 4104000, 4110848, 4123000, 4174281, 4206592, 4342914,
4467528, 4505949, 4511808, 4607064, 4624776, 4673088, …]
这是一个基准测试代码:
// run taxicab(n) for k trials and return the average running time
function benchmark(n, k) {
let t = 0;
k = k || 1; // how many times to repeat the trial to get an averaged result
for(let i = 0; i < k; i++) {
let t1 = new Date();
taxicab(n);
let t2 = new Date();
t += t2 - t1;
}
return Math.round(t/k);
}
最后,我测试了一下:
let T = benchmark(1E7, 3); // 1376 - running time for n = 10 million
let T2 = benchmark(2E7, 3);// 4821 - running time for n = 20 million
let powerLaw = Math.log2(T2/T); // 1.3206693816701993
所以这意味着在这个测试中时间与 n^1.32 成正比。用不同的值重复这个多次总是会产生大致相同的结果:从 1.3 到 1.4。