HackerRank Migratory Birds测试用例异常排查求助
我是JavaScript初学者,正在HackerRank上完成“Migratory Birds”练习,题目要求给定一个记录鸟类种类的数组,返回出现次数最多的鸟类类型(若有多个类型次数相同,返回编号最小的)。我的代码在大部分测试用例都能通过,但有一个长度为124992的大测试用例始终失败,预期输出为3,但我本地用截断的输入测试时能得到正确结果,不清楚问题出在哪。
我的代码:
function migratoryBirds(arr) { let highestCount = 0 let mostCommonType = 0 for(let i=1; i<=Math.max(...arr); i++) { let count = arr.filter(element => element == i).length if(count>highestCount) { highestCount = count mostCommonType = i } } return mostCommonType }
问题测试用例的部分元素:
5 2 2 2 4 1 1 2 4 2 2 2 4 1 2 4 1 2 4 4 3 2 3 1 3 3 4 3 5 2 5 3 4 1 3 2 3 3 3 5 2 4 1 5 4 5 4 4 4 5 3 2 1 1 3 1 1 5 5 3 5 2 2 4 5 2 4 3 2 4 4 5 3 2 3 2 4 5 2 2 3 5 2 3 1 3 3 2 4 3 5 4 3 1 3 3 2 4 4 3 5 3 3 3 5 1 3 5 5 2 5 2 3 4 3 3 2 1 3 1 2 3 2 4 2 3 3 3 3 4 3 3 1 1 5 1 3 4 5 5 3 3 1 5 5 5 5 2 3 1 3 2 3 5 5 1 1 3 4 1 1 2 4 4 4 1 2 3 3 2 1 5 3 1 1 2 2 1 5 2 1 1 4 2 4 5 2 2 2 1 1 1 3 2 4 5 1 4 4 1 5 2 1 4 3 5 4 2 1 5 5 5 2 1 4 5 2 2 1 2 4 3 2 4 3 3 5 3 5 1 4 1 2 4 2 1 5 5 1 1 5 5 1 3 5 2 5 4 1 1 2 1 5 2 3 3 1 1 2 2 5 2 1 3 5 5 4 2 5 5 4 2 1 3 3 1 2 5 5 1 4 4 5 4 3 2 4 5 1 4 1 2 2 4 5 3 3 5 1 4 2 5 1 5 3 3 2 4 3 5 1 2 4 2 3 4 4 4 4 3 4 5 1 2 3 1 5 2 2 3 5 4 5 3 2 3 3 3 1 4 2 3 3 4 4 3 2 2 2 2 1 4 2 3 1 4 4 5 4 1 3 1 2 3 4 3 2 2 3 2 3 5 2 3 3 1 1 3 4 1 2 3 3 4 5 3 2 4 2 2 3 1 3 1 3 1 2 1 1 4 3 3 1 3 4 1 4 4 5 5 2 5 4 2 5 4 1 3 1 2 2 5 4 4 2 2 5 4 2 3 5 5 1 3 1 2 1 2 1 2 5 4 5 4 3 5 1 4 5 1 5 5 2 3 2 3 5 1 1 4 4 5 5 5 4 5 2 4 2 3 3 2 4 2 5 2 3 3 2 4 3 5 3 4 5 5 2 1 4 5 2 1 2 5 1 1 3 3 5 5 4 2 4 3 1 3 1 4 3(已截断)
问题根源
你的代码中使用Math.max(...arr)获取数组最大值,当数组长度极大(比如124992个元素)时,展开数组作为参数传递给Math.max会超出JavaScript函数的参数数量限制,导致Math.max返回NaN。此时循环条件i<=NaN不成立,循环完全不会执行,最终返回初始值0,与预期结果3不符。
修复方案
1. 安全获取数组最大值
替换Math.max(...arr),改用reduce或循环计算最大值,避免参数溢出:
function migratoryBirds(arr) { let highestCount = 0 let mostCommonType = 0 // 用reduce计算最大值,规避参数数量限制 const maxBird = arr.reduce((prev, curr) => Math.max(prev, curr), 0); for(let i=1; i<=maxBird; i++) { let count = arr.filter(element => element == i).length if(count>highestCount) { highestCount = count mostCommonType = i } } return mostCommonType }
2. 性能优化(可选)
原代码每次循环调用filter遍历整个数组,时间复杂度为O(k*n)(k为鸟类类型数)。可以改用一次遍历统计次数的方式,将时间复杂度降到O(n),更适合处理大数组:
function migratoryBirds(arr) { const countMap = {}; let highestCount = 0; let mostCommonType = Infinity; // 一次遍历统计每种鸟类的数量 for (const bird of arr) { countMap[bird] = (countMap[bird] || 0) + 1; } // 遍历统计结果,找出次数最多且编号最小的类型 for (const bird in countMap) { const birdNum = parseInt(bird); if (countMap[bird] > highestCount || (countMap[bird] === highestCount && birdNum < mostCommonType)) { highestCount = countMap[bird]; mostCommonType = birdNum; } } return mostCommonType; }
验证说明
修改后,大数组不会再触发参数溢出问题,同时优化后的代码处理大数组的效率更高,能稳定通过所有测试用例。
内容的提问来源于stack exchange,提问作者user21695378

