修改数组最大值后无法正确获取第二大值的问题求助
修改数组最大值后无法正确获取第二大值的问题求助
我最近在写代码想获取数组中的第二大值,思路是先找到数组的最大值,把所有最大值替换成0,再找新数组的最大值。但实际运行结果和预期不符,想请大家帮忙排查问题。
我的代码如下:
let arr = [2, 3, 30, 3, 40, 4, 8, 70, 5, 2, 72, 5, 2]; function maxValue(nums) { let max = 0; let index; for (let i = 0; i < nums.length; i++) { if (nums[0] > nums[i]) { max = nums[0]; index = i; } else if (max < nums[i]) { max = nums[i]; index = i } } return max; } console.log("the largest value: " + maxValue(arr)); let newArr = arr.map(function(e, i) { if (e === maxValue(arr)) { e = 0; } return e; }); console.log("the second largest value: " + maxValue(newArr));
运行结果是:
the largest value: 72 the second largest value: 5
我预期第二大值应该是70,但实际得到5,完全搞不懂哪里出问题了😭
嗨,我帮你看了下代码,问题主要出在你写的maxValue函数逻辑上,这个函数的遍历逻辑有明显的错误,导致在处理修改后的数组时无法正确找到最大值。
问题根源分析
你的maxValue函数里有两个致命的逻辑问题:
多余且错误的条件分支:
函数里的if (nums[0] > nums[i])这个分支完全是画蛇添足,甚至会破坏最大值的追踪。比如在处理修改后的newArr时,当遍历到原72被改成0的位置(i=10),nums[0]是2,2>0成立,这时候你会把max强制设为2,覆盖之前已经找到的70。后面遍历到i=11的5时,因为2<5,max又被更新为5,之后没有更大的元素触发更新,最终就返回了5,这就是你得到错误结果的原因。初始值设置不合理:
你把max初始设为0,如果数组里全是负数,这个函数直接就失效了,正确的做法应该是把max初始化为数组的第一个元素,或者-Infinity来兼容所有数值情况。
修复后的代码
先把maxValue函数改成正确的最大值查找逻辑,再优化一下数组修改的部分(避免重复计算最大值):
let arr = [2, 3, 30, 3, 40, 4, 8, 70, 5, 2, 72, 5, 2]; // 修复后的最大值查找函数 function maxValue(nums) { // 先处理空数组的边界情况 if (nums.length === 0) return undefined; let max = nums[0]; // 初始化为数组第一个元素 for (let i = 1; i < nums.length; i++) { // 从第二个元素开始遍历即可 if (nums[i] > max) { max = nums[i]; } } return max; } // 先获取一次最大值,避免重复计算 const largestNum = maxValue(arr); console.log("the largest value: " + largestNum); // 生成修改后的数组 let newArr = arr.map(item => item === largestNum ? 0 : item); console.log("the second largest value: " + maxValue(newArr));
运行这段代码后,就能得到你预期的结果:
the largest value: 72 the second largest value: 70
额外高效方案:无需修改数组,一次遍历找第二大值
其实你完全不需要修改数组来实现这个需求,可以一次遍历同时追踪最大值和第二大值,时间复杂度是O(n),比修改数组再遍历的方式更高效:
function findSecondLargest(nums) { if (nums.length < 2) return undefined; let firstMax = -Infinity, secondMax = -Infinity; for (const num of nums) { if (num > firstMax) { // 找到更大的值,把原来的最大值降级为第二大值 secondMax = firstMax; firstMax = num; } else if (num > secondMax && num !== firstMax) { // 找到介于第二大和最大值之间的数,注意:如果数组允许存在多个相同的最大值,比如有多个72,可以去掉`&& num !== firstMax` secondMax = num; } } return secondMax; } console.log("the second largest value: " + findSecondLargest(arr)); // 输出70
这种方法只需要遍历数组一次,性能更好,也更简洁。
内容来源于stack exchange




