秒懂 LeetCode 系列 —— 两数之和

390 阅读3分钟

您的点赞和关注是我坚持写作的最大动力,本人正在寻找测试开发的工作机会,欢迎微信联系: gyx764884989

概要

描述

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

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 示例:

给定 nums = [2, 7, 11,  15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

图形介绍

分析

我们拥有的资源是一个数组和一个数字,这个数字代表两个数字的和,这两个数字从给定的数组中寻找,比如题目给定的是 9 ,我们就可以从数组中找到 2 和 7 ,这就是题目需要的一组结果,我们要做的就是从数组中找出这种数字组合,并获得组合中两个数字的下标

暴力法

暴力法肯定是脑海里第一个迸出的灵感,先以第一个数字为基准,看看后面的数字能否和它凑成结果,如果可以,则返回,如果不行则继续寻找,以第一个数字为基准完成遍历后就使用下一个数字,直到找到题目所需的数字组合,很容易得到以下代码

class Solution {
    public int[] twoSum(int[] nums, int target) {
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) { // 遍历第一个加数后面的每一个数字
                if (nums[j] == target - nums[i]) { // 判断第一个加数与第二个加数的和是否为目标值
                    return new int[] { i, j }; // 找到则返回该数字组合中两个数字的下标
                }
            }
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

如何优化?

首先我们要思考如下问题:

为什么暴力法遍历效果差?

因为我们要寻找两个数字,所以按照暴力法,对于每一个数组中的元素,我们都试图去寻找与之相加满足条件的数字,所以会额外增加一次 O(n) 的时间复杂度,该算法的时间复杂度为 O(n^2)。由于没有额外的数据结构使用,该算法的空间复杂度为 O(1)

如何提升搜索效率?

可以看到,提升该算法效率的关键就是提升搜索的效率,这里我们用到了 HashMap 作为优化工具,它可以带来高效的搜索接口,该接口的 时间复杂度可以达到 O(1), 接下来我们就可以使用如下方案获取最终结果:

原理图

这就是两遍哈希表法,具体代码如下:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>(); // 创建 Hash 表数据结构
        for (int i = 0; i < nums.length; i++) { // 第一遍,构建哈希表
            map.put(nums[i], i);
        }
        for (int i = 0; i < nums.length; i++) { // 第二遍
            int complement = target - nums[i]; // 判断第二个加数是否在 HashMap 中,如果在则查找成功
            if (map.containsKey(complement) && map.get(complement) != i) {
                return new int[] { i, map.get(complement) };
            }
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

其中 map.containsKey(complement) 即为 O(1) 的查找方法,也是效率提升的关键,复杂度分析:

  • 时间复杂度:O(n), 我们把包含有 n 个元素的列表遍历两次。由于哈希表将查找时间缩短到 O(1) ,所以时间复杂度为 O(n)

  • 空间复杂度:O(n), 所需的额外空间取决于哈希表中存储的元素数量,该表中存储了 n 个元素。

第一性原理

该问题其实是一个查找 类型的问题,而两次哈希表法,实质上是一种通过缓存来优化时间效率的手段,通过在 HashMap 这个缓存中查找第二个元素,大大提升了算法效率。

参考