多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
面试中常被问及的一道面试题,其实这道题不难,关键是写出来的算法需要在时间复杂度上尽量做到最优。实现不难,但是要做到让面试官满意那就得多多思考。 # 方法1: 循环+indexOf ## 思路 循环数组,使用目标值减去当前循环的元素,带着计算出的减后的值去数组中寻找有没有这个值,如果有即indexOf不是-1,那当前循环的索引和indexOf返回的索引,即为答案 ## 实现 ``` function findIndexes1 (arr, target) { let currentNum, otherNum, currentIndex, otherIndex for (let i = 0, len = arr.length; i < len; i++) { currentNum = arr[i] // 当前元素如果大于目标值,则直接进行下一轮循环,加快检索速度 if (currentNum > target) { continue } otherNum = target - currentNum otherIndex = arr.indexOf(otherNum) if (otherIndex !== -1) { currentIndex = i break } } return [currentIndex, otherIndex] } ``` ## 说明 这个算法看似只有一个循环,实则不然。因为循环内部使用了indexOf方法,而这个方法底层仍然是靠循环实现的,所以时间复杂度仍然是 On平方 # 方法2 循环+Map ## 思路 思路和方法1其实特别像。只不过是把使用indexOf()在数组中寻找的方法替换为使用Map的has()在Map中寻找的方法。消除了嵌套循环,从而性能得到提升。具体做法是:先将数组转为Map,其中key为数组中的数值,value为数值的下标索引。然后循环数组,计算出另一个值,使用has()寻找是否有这个值,若找到,使用get()获取索引,跳出循环;若没找到,继续下轮循环。 ## 实现 ``` function findIndexes2 (arr, target) { let map = new Map() // 数组转Map key为数值 value为下表索引 arr.forEach((item, index) => { map.set(item, index) }) let currentIndex, otherIndex, currentNum, otherNum for (let i = 0, len = arr.length; i < len; i++) { currentNum = arr[i] if (currentNum > target) { continue } otherNum = target - currentNum if (map.has(otherNum)) { currentIndex = i otherIndex = map.get(otherNum) break } } return [currentIndex, otherIndex] } ``` # 综合性能测试 生成一个测试数组,这个数组共有100002个元素,其中前100000个元素均为1,最后两个元素分别是2和3。目标值设计的是5。这样做的目的是程序需要循环好多次才能找到结果,从而对比出性能的差异。 ``` function getArr () { let arr = [] let i = 0 while (i < 100000) { arr.push(1) i++ } arr.push(2, 3) return arr } ``` ``` let start = Date.now() console.log(findIndexes1(getArr(), 5)) let end = Date.now() console.log(end - start) // chrome 5753ms ``` ``` let start = Date.now() console.log(findIndexes2(getArr(), 5)) let end = Date.now() console.log(end - start) // chrome 35ms ``` 结果不言而喻,一个四位数,一个两位数,这性能差异完全不在一个数量级。