# 两数之和 (opens new window)

给定一个整数数组 nums  和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

这应该是绝大部分人人生中的第一道 LeetCode 题吧

# 朴素法

朴素法的思路和选择排序的思路差不多,反正只要我找到了两个能够满足题目要求的组合就可以了,所以,算法的实现如下:

var twoSum = function (nums, target) {
  if (nums.length < 2) {
    return;
  }
  for (let i = 0; i < nums.length - 1; i++) {
    for (let j = i + 1; j < nums.length; j++) {
      if (nums[i] + nums[j] === target) {
        return [i, j];
      }
    }
  }
};

可以看到,朴素法的时间复杂度是O(n²),因为没有用到额外的空间,所以空间复杂度为O(1)

# 哈希法

这题能够使用哈希表进行解答的人一定是动过脑筋的人。

首先遍历是肯定少不了的,在遍历的时候,我们既然知道当前的数字,也知道总和,那我们我们可以算出差值,如果这个差值在数组中存在,那么就可以得到结果,如果不存在,继续尝试。

怎么样快速的检索一个东西是否存在,根据我们之前学过的理论,哈希表能够在O(1)的时间内检索,平衡二叉树和二分查找能够在O(log n)的时间内检索,二分查找肯定是搞不定的,二分查找必须要在有序的条件下才能使用,如果用平衡二叉树,我们还要根据其值的大小建立树,不仅非常麻烦,复杂度还不如哈希表,显然这题,用哈希表才比较符合场景。

var twoSum = function (nums, target) {
  if (nums.length < 2) {
    return;
  }
  // 根据值建立哈希映射
  const map = Object.create(null);
  nums.forEach((num, idx) => {
    map[num] = idx;
  });
  for (let i = 0; i < nums.length; i++) {
    let a = nums[i];
    let b = target - a;
    let otherIdx = map[b];
    // 存在并且不是自己,自己跟自己肯定不行
    if (typeof otherIdx !== "undefined" && otherIdx !== i) {
      return [i, otherIdx];
    }
  }
};

建立哈希的时间复杂度是O(N),空间复杂度是O(N)

循环查找的时间复杂度是O(N)

最终得时间复杂度是 2*O(N),省略系数,得O(N),空间复杂度是O(N)