LeetCode 题解——两数之和

150 阅读1分钟

这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战

大家好,我是前端西瓜哥,今天我们来解析 LeetCode 的第一道题目:两数之和。

image-20220215220453983.png

暴力破解

最容易想到的方法是双重遍历,用暴力穷举的方式找到答案。

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

我们用到两个指针,指针 i 每次向后移动,指针 j 都会遍历 i 之后的所有数字拿到 nums[j],然后将它们一个个和 nums[i] 相加看看,看看和等不等于 target。

如果等于 target,返回对应的索引值数组,否则继续尝试,直到遍历结束。

因为题目说了一定能找到,所以我们并不需要返回一个 [-1, -1] 来表示没有找到。但实际开发中并不会这么理想,还是要考虑找不到的情况的。

空间复杂为 O(1)。用了双重循环,因此时间复杂度 O(n^2)。效率很低,很显然并不是最优解。

哈希表

双重遍历的方式低效,因为它多次访问了同一个数组元素。如果我们能够改善一下,每个数组元素只访问一次,效率就能极大提升。

于是我们需要用到一种名为哈希表的数据结构。

哈希表,简单来说,就是可以通过 a 拿到 b,在表现上,是一种映射关系。但它效率很高,时间复杂度是 O(n)

我们先看看代码实现:

function twoSum(nums: number[], target: number): number[] {
  const map: { [key: number]: number } = {};
  for (let i = 0; i < nums.length; i++) {
    const num = nums[i];
    const matchNum = target - num;
    if (map[matchNum] !== undefined) { // 看看匹配的另一个数是否已被访问过
      return [map[matchNum], i];
    }
    map[num] = i; // 将当前数字标记为已访问,并记录好它的索引值
  }
};

这里用哈希表记录了 数值 -> 索引 的映射关系。

当我们遍历拿到数组元素时,我们看看这个数字 num 对应的另一个数字 target - num 是否在哈希表中。

如果存在,说明它被访问过,然后通过映射拿到对应的索引值,和 num 的索引值一起返回,遍历结束。

否则我们通过将当前的 num 和对应的索引存到哈希表的方式,来标记为已访问。

哈希表解法的时间复杂度 O(n),空间复杂度为 O(n)