双指针方式
思路:先对数组进行从小到大排序后,定义左(l) 右(r)两个指针,取出两个数相加之和 sum。
- 如果 sum === target 相同,则将下标放入到数组中
- 如果 sum > target,说明右边的数有点大,则把左指针 l 向右移动一位
- 如果 sum < target,说明左边的数有点小,则把右指针 r 向左移动一位
注意: 不对传入的数组进行排序,否则即便找到了之和与 target 相同的两个数,下标也是错误的,解决的方法是,先把下标存入到数组indexs中,这时下标是从 0 开始到 length - 1 结束, 然后用 sort 对 indexs 进行打乱,打乱的规律是按照原数组排序的方式进行。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
if(nums.length === 0) return [];
// 按照下标存放在数组中
let indexs = Array.from(Array(nums.length), (item,index) => index)
// 把下标按照原数组排序的方式打乱
indexs.sort(function(a, b) {return nums[a] - nums[b]});
let result = [], r = 0, l = nums.length - 1;
while(r < l) {
const sum = nums[indexs[r]] + nums[indexs[l]];
if(sum === target) {
result.push(indexs[r]);
result.push(indexs[l]);
break;
}else if(sum < target) {
r++
} else if(sum > target) {
l--
}
}
return result;
};
console.log(twoSum([2,7,11,15], 9));
console.log(twoSum([3,2,4], 6)); //[2,3,4]
以上的关键思路在于原数组保持不变,还要从小到大排序,这时打乱下标的方式来表示数组中的元素在排序后应该在的位置。
const arr = [3,1,2]
// 存的是下标
const indexs = [1,3,0] // 表示第一个数,应该是下标为1对应的数字
映射关系
思路: 使用目标值 target 和每一个值相减,把相减的结果作为 key 和 本轮值的下标存在映射对象中,当进行到下一轮,如果该值存在映射表中,则说明有相加为目标值的数,返回即可。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
if(nums.length === 0) return []
if(nums.length === 1) return []
const n = {} // 映射关系
for(let i = 0; i < nums.length; i++){
// 如果差值存在,则找到了
if(nums[i] in n){
return [n[nums[i]], i]
}
n[target - nums[i]] = i // 差值存在映射表中,对应下标
}
return []
};