JavaScript中BigInt无法处理超大数的问题求解(AoC2022 Day11)
解决Advent of Code 2022 Day 11 Part 2的BigInt溢出与性能问题
你的问题根源在于:哪怕用BigInt,10000轮循环里数值会指数级膨胀,最终超出引擎能处理的BigInt上限,同时超大数的运算会拖慢性能。但题目核心是判断数值能否被某个除数整除,完全不需要保留完整的超大数——用模运算优化就能彻底解决。
关键优化思路
题目里所有猴子的检验除数都是质数(互质),计算这些除数的乘积作为公共模commonMod,每次数值操作后对commonMod取模。这样数值会被限制在commonMod范围内,既不会溢出,也能保证后续的整除判断结果完全正确。
具体修改步骤
- 计算公共模:遍历所有猴子,把它们的除数相乘得到
commonMod(用BigInt) - 修改数值处理逻辑:每次完成猴子的加/乘/平方操作后,立即对
commonMod取模,替换原来直接保留大数的逻辑 - 注意Part2特性:不要保留Part1里的除以3的操作(Part2没有这个减负步骤)
代码示例(对应你的逻辑调整)
假设你原来的数值操作代码是这样:
// 原有操作:生成超大数 function applyOperation(oldValue, monkey) { if (monkey.operation === 'multiply old') { return oldValue * oldValue; } else if (monkey.operation.startsWith('multiply')) { const num = BigInt(monkey.operation.split(' ')[2]); return oldValue * num; } else { const num = BigInt(monkey.operation.split(' ')[2]); return oldValue + num; } }
修改后:
// 先计算所有除数的乘积作为公共模 const commonMod = monkeys.reduce((total, monkey) => total * monkey.divisor, 1n); // 优化后的操作:取模控制数值大小 function applyOperation(oldValue, monkey) { let newValue; if (monkey.operation === 'multiply old') { newValue = oldValue * oldValue; } else if (monkey.operation.startsWith('multiply')) { const num = BigInt(monkey.operation.split(' ')[2]); newValue = oldValue * num; } else { const num = BigInt(monkey.operation.split(' ')[2]); newValue = oldValue + num; } // 关键步骤:取模,避免大数膨胀 return newValue % commonMod; }
原理说明
对于任意整数x和除数d,因为commonMod是d的倍数(由所有除数相乘得到),所以x % commonMod % d === x % d。这意味着用取模后的数值判断是否能被d整除,结果和用原始超大数判断完全一致,但数值大小被牢牢控制,不会出现溢出或性能下降。
额外注意事项
- 确保所有涉及数值的变量都用BigInt类型,避免不必要的类型转换
- 循环中尽量减少变量的重复创建,提升运行效率
内容的提问来源于stack exchange,提问作者Anthony Bias
相关产品推荐
相关产品推荐

