leetcode每天一题:【两数之和】(简单)

195 阅读3分钟

这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

题目描述

leetcode题目地址

提供一个整数数组和一个目标数target,你需要在在数组中找到2个数,它们的和为target,并通过数组形式返回它们的索引。

举个例子:

数组: [5,7,9]
target: 16
返回 [1,2]

数组: [2,5,7,4]
target: 6
返回 [0,3]

注意:一个数不能重复使用。比如数组:[3,3], target: 6 ,你不能返回[0,0],可以是[0,1]或者[1,0]

思路分析

第一种方法

常规做法就是针对数组做2次遍历,遍历嵌套

外层的遍历是从0开始,到数组的倒数第二个结束

内层的遍历是从外层的遍历索引加1开始(为什么要加1,因为一个数不能重复使用),到数据的最后一个结束。

然后判断,如果外层的元素和内层的元素相加等于target,则可以把索引记录到新数组中,然后break。

这个break只是break内层的遍历,外层的还没有break。

这时候可以在外层判断新数组的长度,如果大于0则代表找到了,然后break。

返回新数组就可以了。

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
  let arr = []
  for (let i = 0; i < nums.length - 1; i++) {
    for (let j = i + 1; j < nums.length; j++) {
      if (nums[i] + nums[j] === target) {
        arr = [i, j]
        break
      }
    }
    if (arr.length) break
  }
  return arr
};

上面使用了遍历嵌套,时间复杂度是O(n^2),那么可以在时间复杂度小于O(n^2)的情况下做出来吗?

答案是可以的。

第二种方法

这里就需要用到额外空间,我这里需要使用到map(用对象{}也行)

遍历数组,把数组的value设置成map的key,索引设置成map的value。

然后再次遍历数组(非嵌套),用target减去当前数组遍历的值,调用map.get方法,看看是否有的索引,如果有,则证明找到了,直接返回对应的索引数组即可。

这里需要注意,要判断map.get方法得到索引和遍历的索引是否相等(因为一个数不能重复使用),并且是不是undefined,如果都不是,才正确并返回数组。

版本1:

var twoSum = function (nums, target) {
  const map = new Map()
  for (let i = 0; i < nums.length; i++) {
    map.set(nums[i], i)
  }
  for (let i = 0; i < nums.length; i++) {
    const j = map.get(target - nums[i])
    if (i !== j && j !== undefined) return [i, j]
  }
  return []
};

还有另外一个版本,这个思路差不多,只不过它并没有先把map设置一遍数组的值和索引,而是一边遍历和一边查询map和设置map,如果查询到了,则直接返回,否则继续设置map的keyvalue

版本2:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
  const map = new Map()
  for (let i = 0; i < nums.length; i++) {
    const val = target - nums[i]
    if (map.has(val)) return [i, map.get(val)]
    map.set(nums[i], i)
  }
  return []
};

这样时间复杂度都是O(n)。

image.png