首先,弄清楚你可以在内存中存储多少个数字。对于此示例,假设您可以存储 999 个数字。
您的第一步是预先计算 0-999 之间所有数字的数字乘积,并将其存储在内存中。所以,你会有一个数组:
multLookup = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 2, 4, 6, 8, 10, 12, 14, 16, 18,
0, 3, 6, 9, 12, 15, 18, 21, 24, 27,
0, 4, 8, 12, 16, 20, 24, 28, 32, 36,
...]
现在,您可以将您的号码分解为一组 3 位数字。例如,如果您的号码是1739203423
,您会将其分解为1
、739
、203
和423
。你会在你的数组中查找每一个multLookup
,并将结果相乘,如下所示:
solution = multLookup[1] * multLookup[739] * multLookup[203] * multLookup[423];
使用这种方法,您的计算速度将提高 3 倍(因为我们选择了 999 个项目存储在内存中)。要将其加快 5 倍,请将 99999 个数字存储在内存中并按照相同的步骤操作。在您的情况下,将其加快 5 意味着您将在29.2 seconds 内达到您的解决方案。
注意:增益与您在内存中存储的数字数量并不完全呈线性关系。请参阅此答案下评论中的 jogojapan 的推理,了解为什么会这样。
如果您对数字显示的顺序或数字的范围有更多了解(例如您的输入仅在 [0, 10000] 范围内),您可以使该算法更智能。
在您的示例中,您使用 for 循环从 0 迭代到 1000000000。在这种情况下,这种方法将非常有效,因为内存不会非常频繁地出现页面错误并且缓存未命中次数会更少。
可是等等!您可以使这更快(对于您特定的 for 循环迭代示例)!怎么样,你问?缓存!假设您正在处理 10 位数字。
假设您从8934236000
. 根据内存解决方案中的 999 位数字,您可以将其分解为8
、934
、236
和000
。然后你会乘以:
solution = multLookup[8] * multLookup[934] * multLookup[236] * multLookup[0];
接下来,您将8934236001
, 分解为8
, 934
, 236
, 和001
, 并相乘:
solution = multLookup[8] * multLookup[934] * multLookup[236] * multLookup[1];
依此类推……但我们注意到前三个查找在接下来的 997 次迭代中是相同的!所以,我们缓存它。
cache = multLookup[8] * multLookup[934] * multLookup[236];
然后我们像这样使用缓存:
for (int i = 0; i < 1000; i++) {
solution = cache * i;
}
就这样,我们几乎将时间减少了 4 倍。因此,您采用约 29.2 秒的解决方案,然后将其除以 4 以在约 7.3 秒内遍历所有十亿个数字