原题
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
给定 nums = [2, 7, 11, 15], target = 9。因为 nums[0] + nums[1] = 2 + 7 = 9。所以返回 [0, 1]
思路
最简单的方法是通过两层for循环进行遍历, 使用暴力的查找两个子元素。但是这种方法的时间复杂度为O(n^2)。在大数据量的测试用例的情况下执行时间超时。那么我们有什么办法可以将时间复杂度降下来吗?这时我们可以用到HashMap。通过HashMap我们可以将时间复杂度降为O(2n)。如果是有序数组的情况下, 时间复杂度可以是O(n), 详见下题。
1、使用map
这个思路比较简单,而且复杂度低,但是需要对map有对应的应用和理解;
通过这个方法,我学习到的一点是:对应的数组中的某个数和数字下标用map对应起来。通过map的key、value把数组中的值和它对应的下标对应起来,很巧妙的结合起来。
var twoSum2 = function (nums, target) {
const len = nums.length; // 获取长度
let map = new Map() //定义map
for (let i = 0; i < len; i++) {
const diff = target - nums[i] // 拿到目标值与当前值的差值
if (map.has(diff)) { // 判断map里是否存在,若存在则说明:当前值nums[i]+map.get(diff)=target
return [map.get(diff), i] // 直接返回对应的下标
} else {
map.set(nums[i], i) // 不存在,则存当前值以及对应的下标,继续循环
}
}
return [] // 没找到
};
2、使用两个for循环
var twoSum2 = function (nums, target) {
// 暴力法
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] === target - nums[j]) return [i, j]
}
}
return []
}
3、先记录下标,然后对数组进行排序,使用双指针法(这个方法比较复杂,是借鉴的三数之和的方法)
var twoSum = function (nums, target) {
let [res, arr, len] = [[], [], nums.length];
nums.forEach((item, index) => {
arr.push({ key: index, value: item })
})
arr.sort((a, b) => a.value - b.value)
// 数组
console.log(arr)
for (let i = 0; i < len - 1; i++) {
let k = len - 1
while (i < k) {
console.log(arr[i])
console.log(arr[k])
let sum = arr[i].value + arr[k].value
console.log(sum)
if (sum < target) {
i++
if (i > 0 && arr[i - 1].value === arr[i].value) {
i++
}
} else if (sum > target) {
k--
if (k > 0 && arr[k + 1].value === arr[k].value) {
k--
}
} else {
console.log(arr[i])
console.log(arr[k])
res.push(arr[i].key, arr[k].key)
return res
}
}
}
};