这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战
题目描述
提供一个整数数组和一个目标数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的key和value。
版本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)。