JS求小于输入数的3/5倍数和时reduce空数组报错排查
3或5倍数求和问题报错排查与实现方案
报错原因
你遇到的Reduce of empty array with no initial value错误,加上去重逻辑不生效的问题,根源有两个:
- 分支判断逻辑错误:你用
else if串联3和5的倍数判断,所有同时是3和5倍数的数(比如15、30)会先命中3的倍数判断,直接被推入multiplesOfThree数组,永远不会进入5的倍数判断分支,multiplesOfFive里从一开始就没有公倍数,你后面写的交集去重逻辑完全不生效。 - reduce空值防护不全:你只给
intersectionResult加了空数组兜底,但multiplesOfThree和multiplesOfFive完全可能是空数组——比如传入参数为2时,两个数组都没有元素。Array.reduce()如果不传第二个参数作为初始值,对空数组调用时会直接抛出你看到的类型错误,这就是报错的直接触发点。
另外你代码里循环从0开始推入数字,0是所有非零整数的倍数,虽然加0不影响求和结果,但和题目示例的自然数计数逻辑不一致,属于冗余逻辑。
修正后的原思路代码
保留你用数组存储、容斥求和的思路,修正分支错误,给所有reduce传入初始值0即可解决问题:
function solution(number) { if (number < 0) { return 0; } let multiplesOfThree = []; let multiplesOfFive = []; // 直接遍历判断,无需先生成全量数字数组 for (let i = 1; i < number; i++) { if (i % 3 === 0) { multiplesOfThree.push(i); } // 去掉else,独立判断5的倍数,公倍数会同时进入两个数组 if (i % 5 === 0) { multiplesOfFive.push(i); } } const reducer = (accumulator, curr) => accumulator + curr; // 所有reduce传入初始值0,空数组调用也不会报错 const sum3 = multiplesOfThree.reduce(reducer, 0); const sum5 = multiplesOfFive.reduce(reducer, 0); // 计算重复计数的公倍数和 const intersection = multiplesOfThree.filter(x => multiplesOfFive.includes(x)); const sumDuplicate = intersection.reduce(reducer, 0); return sum3 + sum5 - sumDuplicate; }
更简洁的实现方案
实际上不需要拆分数组,遍历一次直接判断数字是否符合条件累加即可,天然避免重复计数问题,代码更短、逻辑更清晰:
function solution(number) { if (number < 0) return 0; let total = 0; for (let i = 1; i < number; i++) { if (i % 3 === 0 || i % 5 === 0) { total += i; } } return total; }
如果追求最高性能(处理超大数字也不会有遍历耗时),可以直接用等差数列求和公式结合容斥原理,时间复杂度O(1):
- 小于n的3的倍数和 = 3 * k * (k+1) / 2,其中k是小于n的3的倍数的个数
- 同理计算5的倍数和,减去重复计算的15(3和5的最小公倍数)的倍数和即可
function solution(number) { if (number < 0) return 0; const getSum = (divisor) => { const count = Math.floor((number - 1) / divisor); return divisor * count * (count + 1) / 2; } return getSum(3) + getSum(5) - getSum(15); }
内容的提问来源于stack exchange,提问作者lappodamy
相关产品推荐
相关产品推荐

