【问题标题】:Interview live-coding - Find Second Biggest number in array采访实时编码 - 查找数组中的第二大数字
【发布时间】:2018-04-19 15:18:33
【问题描述】:

快速元信息:

我一直在为这个问题寻找真正合适的地方,stackoverflow 上没有。仍然回答这个问题需要编程经验。


我是一名高级软件工程师,并在拥有 250 名员工的公司中负责 node.js 开发人员,因此我正在进行技术面试。我在这里才 2 个月,所以我没有太多经验(以前的公司规模小得多,所以很少招聘新的后端人员)。

面试部分是实时编码,通常通过 Skype。我认为这很重要,因为有些人真的什么都做不了。

但有一件事让我很烦恼——很多人在“查找数组中的第二大数”任务上失败了,我认为这很容易。

我通常只在有限的情况下给他们写这段代码——不要对数组进行排序,也不要对数组使用任何特殊函数:

const _arr = [1, 7, 8, 5, 4, 2];

function findSecondBiggest(arr){
}

console.log(findSecondBiggest(_arr));

任务是将代码写入找到第二大数字的函数中。我认为这只是“检查”问题,并且对于大多数程序员来说都是“去做”。

即使是看起来很有前途的开发人员也经常在这方面失败。我知道他们承受着压力,但我什至试图引导他们,让他们平静下来,他们至少有 20 分钟的时间(通常甚至 30 分钟,因为我在通话中多待了 10 分钟,让他们有机会完成它)。 很多开发人员看起来很有前途——他们有很好的经验和知识,能够评估他们为什么要使用这个框架/技术......但是却不能做到这一点。

我已咨询技术主管,他说如果他们无法做到这一点,我们应该停止 - 因为我们正在寻找程序员并且我们期待编写代码。该公司还对中高级开发人员感兴趣。

这个任务真的那么难吗?或者它是否真正表明您是否可以提出至少简单的算法并实现它?

我也接受使用两个 for 循环的解决方案,当第一个找到最大数字时,第二个 for 循环找到第二大数字,因为它仍然是 O(n)。

【问题讨论】:

  • 我知道这将主要基于意见 - 但这绝对不是一个难题。您的候选人是否知道会有编程问题?
  • 这确实是一个非常琐碎的问题。
  • 我希望我能得到这个问题。它远非微不足道,事实上它与基本的算法素养有关。我的回答是对 Lewis Carroll 的一个小介绍(他提出了这个问题,但没有正确解决),然后按照 Stepanov 的binary counter 进行实施。我不认为这 20 分钟是足够的。 Stepanov 就这个问题做了 10 场讲座。

标签: javascript arrays node.js algorithm


【解决方案1】:

这并不难,它会让你思考。我肯定会在面试中使用这种问题。不过,我会准备一些指导性问题:

  1. 如何找到最大的?
  2. 你怎么知道一个数字是第二个? 等等……

这是我可爱的解决方案(从@BrettDeWoody's answer 窃取的测试用例)。您可以使用标准方法找到最大的数字,然后再添加最小的数字。

const _arr = [1, 7, 8, 5, 4, 2];

function findSecondBiggest(arr){
  const r = {};

  for(let i = 0; i < arr.length; i++) {
    if(r.first === undefined || arr[i] > r.first) {
      r.second = r.first;
      
      r.first = arr[i];
    } else if (arr[i] !== r.first && (r.second === undefined || arr[i] > r.second)) {
      r.second = arr[i];
    }
  }
    
  return r.second; // for arrays with length under 2, the answer would be undefined
}

console.log(findSecondBiggest([1, 7, 8, 5, 4, 2])); // 7
console.log(findSecondBiggest([1, 0, 0, 0, -1, -2])); // 0
console.log(findSecondBiggest([2, 2, 1, 0, -1, -2, 2])); // 1
console.log(findSecondBiggest([1, 1, 1, 1, 1])); // undefined
console.log(findSecondBiggest([0, 0, 0, 1])); // 0
console.log(findSecondBiggest([1, 2, 3, 4])); // 3
console.log(findSecondBiggest([Infinity, -Infinity])); // -Infinity
console.log(findSecondBiggest([-Infinity, Infinity])); // -Infinity
console.log(findSecondBiggest([1, 2, 3, 4, 5, Infinity])); // 5
console.log(findSecondBiggest([1])); // undefined

【讨论】:

  • “不要对数组使用任何特殊函数”我想使用归约实际上算作这样做。可能已经保存了用于编写外循环的样板代码。如果数组包含一个负数后跟一个零,也会失败,因为这会在错误的时间触发!r.first
  • 我实际上会接受这个解决方案,有一些边缘情况,但整个算法仍然写在这里。
  • @Ext3h - 在这种情况下 Array#reduce 只不过是一个美化的循环。但是,我已将其更改为 for 循环。 !r.first/second 是对的,所以我将其更改为 r.first/second === undefined。
  • 虽然它仍然不是一个理想的解决方案。就逻辑和运行时间复杂度而言,它非常好。但是,在循环中不使用严格类型(潜在的undefined)可能会阻止 JIT 编译器进行重大优化。预初始化对象,并将不相等的检查拉出循环可以允许优化。
【解决方案2】:

完全同意smac89的观点。作为工程招聘团队的成员和代码导师,我不喜欢带有不切实际限制的面试问题。

与其问一个候选人在技术面试之外永远不会遇到的问题,不如提出一个与候选人将要从事的工作相关的具有挑战性的问题,并让候选人展示他们对他们将使用的语言和技能的了解.

作为一个很好的例子,一位朋友最近分享了一个前端面试问题 - 在时间限制内构建一个没有任何库的简单应用程序。

使用提供的 API 端点(使用 ?page=N 查询参数返回分页结果),应用程序必须进行用户搜索,检索所有结果(可能涉及多页结果),按字母顺序对所有结果进行排序,并一次显示所有结果。这需要对fetchPromise(和Promise.all)、数组方法、事件侦听器和原生JavaScript DOM 操作的了解(更重要的是,意识)。

候选人可以查阅任何文档,并根据需要使用任何内置方法。只要候选人对内置的 JS 方法、Fetch API、Promises 等有点熟悉,时间限制就足够了。

IMO,一个近乎完美的面试问题(至少对于前端开发人员而言)。

我的 2 美分。

这是我对以下问题的解决方案:

  • 使用 ES5
  • 不使用数组方法(Array.length 除外)
  • 处理边缘情况,例如同构数组、长度为 1 的数组等

function findSecondBiggest(arr, startInd){
  let start = startInd || 0;
  let largest = arr[start];
  let secondLargest = null;
  const arrLength = arr.length;
  
  if (start === arrLength - start) {
    return null;
  }
    
  for (var i = start + 1; i < arrLength; i++) {
    largest = arr[i] > largest ? setSecond(largest) && arr[i] : largest;
  }
  
  function setSecond(num, check) {
    secondLargest = num;
    return true;
  }
  
  if (secondLargest === null) {
    arr[arrLength] = arr[0];
    return findSecondBiggest(arr, start + 1);
  }
  
  return secondLargest;
}

console.log(findSecondBiggest([1, 7, 8, 5, 4, 2]));
console.log(findSecondBiggest([1, 0, 0, 0, -1, -2]));
console.log(findSecondBiggest([2, 2, 1, 0, -1, -2, 2]));
console.log(findSecondBiggest([1, 1, 1, 1, 1]));
console.log(findSecondBiggest([0, 0, 0, 1]));
console.log(findSecondBiggest([1, 2, 3, 4]));
console.log(findSecondBiggest([Infinity, -Infinity]));
console.log(findSecondBiggest([-Infinity, Infinity]));
console.log(findSecondBiggest([1, 2, 3, 4, 5, Infinity]));
console.log(findSecondBiggest([1]));

【讨论】:

    【解决方案3】:

    实际上,开发人员会走阻力最小的道路。也就是说,他们将对数组进行排序并取倒数第二个元素。更少的代码编写和更少的思考。在我的书中取得了胜利。

    因此,您必须考虑的问题是,您是希望开发人员能够记住如何从头开始正确实现该算法(可能有问题),还是希望开发人员能够重用现有方法以在最短的时间内找到解决方案,几乎可以忽略不计的时间损失,并且几乎没有错误。

    我的意思是,您最后一次想在数百万个元素的数组中找到第二大元素是什么时候?大多数开发人员可能只会选择我最初描述的方法(排序并取第二大),如果发现代码是任何性能问题的瓶颈,则将优化留给 O(n) 再做一次。

    【讨论】:

    • 我明白你的意思,但不完全同意。这个任务的原因绝对不是“需要知道算法”,而是为了证明你有一些分析思维,你可以把它写成代码。我在想“找到第二大数字”很容易证明这一点......那么你的方法或任务是什么来证明这一点的一些实时编码?
    • @libik,你必须小心不要被“分析”之类的词带走。根据您刚才所说的,在我看来,您更重视引入更多复杂性的开发人员,而不是重用现有内容的开发人员。一切都有时间,现在不是为可以用两行短代码解决的问题创新过度设计的解决方案的时候。留给我,我会向潜在员工提出代码库中经常遇到的问题。评论太短了,我会继续下一个
    • 可能是数据库查询、实现服务、与某个端点通信、探索减少发送数据量的方法、不同的缓存方式等。这些对你来说很重要,所以你在招聘时应该关注那些。当然,除非在列表中找到第二大值对您很重要,否则您应该将该方法编写为公司基础库的一部分并继续前进。我敢肯定,除了一个简单的max 函数之外,还有其他需要创新的东西
    【解决方案4】:
    const _arr = [1, 7, 8, 5, 4, 2];
    
    function findSecondBiggest(arr) {
        if(arr.length < 2) {
            return undefined;
        }
        var first = arr[0];
        var second = arr[1];
        if(second > first) {
            [first, second] = [second, first];
        }
        for(var i = 2; i < arr.length; i++) {
            var tmp = arr[i];
            if(tmp > first) {
                [first, second] = [tmp, first];
            } else if(tmp > second) {
                [first, second] = [first, tmp];
            }
        }
        return first != second ? second : undefined;
    }
    
    console.log(findSecondBiggest(_arr));
    

    不,我不会说这是一个非常难的问题。尽管有一些问题很容易让处于压力下的人感到沮丧:

    • 处理错误输入(输入元素不足)
    • 输入头部的特殊处理
    • 如果您不了解 ES6 语法,请交换变量
    • 混合索引和值

    所以虽然不难,但有几个缓存很容易让候选人卡住,或者让他们感到困惑。

    【讨论】:

      【解决方案5】:

      var a = [1, 7, 8, 5, 4, 2];

         for (var i = 0; i < a.length ; i++) {
             var big = 0;
             for (var j = 0; j < a.length ; j++) {               
                 if (a[j] > a[i]) big++;
             }           
             if (big == 1) {
                 return a[i];
             }
         }
      

      并使用预定义的方法

      a[a.sort().length-2]
      

      【讨论】:

        猜你喜欢
        • 2011-02-06
        • 1970-01-01
        • 2022-12-31
        • 1970-01-01
        • 2017-01-04
        • 1970-01-01
        • 2018-04-07
        • 2023-01-19
        • 2018-09-22
        相关资源
        最近更新 更多