双指针方式

思路:先对数组进行从小到大排序后,定义左(l) 右(r)两个指针,取出两个数相加之和 sum

  1. 如果 sum === target 相同,则将下标放入到数组中
  2. 如果 sum > target,说明右边的数有点大,则把左指针 l 向右移动一位
  3. 如果 sum < target,说明左边的数有点小,则把右指针 r 向左移动一位

注意: 不对传入的数组进行排序,否则即便找到了之和与 target 相同的两个数,下标也是错误的,解决的方法是,先把下标存入到数组indexs中,这时下标是从 0 开始到 length - 1 结束, 然后用 sort 对 indexs 进行打乱,打乱的规律是按照原数组排序的方式进行。

  1. /**
  2. * @param {number[]} nums
  3. * @param {number} target
  4. * @return {number[]}
  5. */
  6. var twoSum = function(nums, target) {
  7. if(nums.length === 0) return [];
  8. // 按照下标存放在数组中
  9. let indexs = Array.from(Array(nums.length), (item,index) => index)
  10. // 把下标按照原数组排序的方式打乱
  11. indexs.sort(function(a, b) {return nums[a] - nums[b]});
  12. let result = [], r = 0, l = nums.length - 1;
  13. while(r < l) {
  14. const sum = nums[indexs[r]] + nums[indexs[l]];
  15. if(sum === target) {
  16. result.push(indexs[r]);
  17. result.push(indexs[l]);
  18. break;
  19. }else if(sum < target) {
  20. r++
  21. } else if(sum > target) {
  22. l--
  23. }
  24. }
  25. return result;
  26. };
  27. console.log(twoSum([2,7,11,15], 9));
  28. 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 []
};