You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

修改数组最大值后无法正确获取第二大值的问题求助

修改数组最大值后无法正确获取第二大值的问题求助

我最近在写代码想获取数组中的第二大值,思路是先找到数组的最大值,把所有最大值替换成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函数里有两个致命的逻辑问题:

  1. 多余且错误的条件分支
    函数里的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,这就是你得到错误结果的原因。

  2. 初始值设置不合理
    你把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

火山引擎 最新活动