题目
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
2 <= nums.length <= 10^4
-10^9 <= nums[i] <= 10^9
-10^9 <= target <= 10^9
- 只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n^2)
的算法吗?
此乃 Leetcode 第一题,搜题解找到了代码随想录的讲解,按照其中的讲解跟着敲了一遍,顺带学习了一下哈希表的知识。(同时参考了这个关于哈希表的视频)
先来看代码随想录上总结中的四个问题
为什么会想到用哈希表?
查询一个元素是否出现过,或是一个元素是否存在集合中时,比如你要的和为9,现在遍历到了5,就要思考之前是否遍历过4。
- 在遍历的同时,记录一些信息,以省去一层循环,这是“以空间换时间”的想法。
- 需要记录已经遍历过的数值和它所对应的下标,可以借助查找表实现。
- 题目没有要求key(数组元素)有序,所以使用哈希表而不是平衡二叉搜索树。(这是两个常用的查找表的实现)
哈希表为什么用map?
- 因为本题,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。
本题map是用来存什么的?
- 用来存放我们便利访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)
map中的key和value用来存什么的
- {key:数组元素,value:数组元素对应的下标}
- 题目要求查找数组元素是否出现过,所以数组元素为key
思路
复杂度分析
两层for循环的暴力解法的时间复杂度为O(n^2)。通过哈希表可以将寻找target – nums[i] 的时间复杂度变为O(1),因为每次遍历后都会把遍历过的元素放进集合map中,那么我们最差的情况也就是遍历到数组中最后一个数才会在map中找到对应的数。时间复杂度跟元素数量(或者说数组长度)有关,即时间复杂度为O(n)
过程
Java 代码
class Solution {
public int[] twoSum(int[] nums, int target) {
// 首先,创建一个长度为2的结果数组res,并检查输入数组nums是否为空或长度为0。如果是,就直接返回res
int[] res = new int[2];
if (nums == null || nums.length == 0){
return res;
}
Map<Integer, Integer> map = new HashMap<>();// 创建一个哈希映射map,用于存储数组中的每个元素和它的索引。
// 遍历输入数组nums。对于数组中的每个元素,计算target减去该元素的值,得到temp。
for(int i = 0; i < nums.length; i++){
int temp = target - nums[i];
// 检查map中是否包含temp作为键。如果包含,说明找到了两个数的和等于target,这两个数就是当前元素和map中键为temp的元素。将这两个元素的索引分别存储在res[1]和res[0]中,然后跳出循环。
if(map.containsKey(temp)){
res[1] = i;
res[0] = map.get(temp);
break;
}
map.put(nums[i], i);// 如果map中不包含temp,就将当前元素和它的索引添加到map中。
}
return res;// 遍历结束后,返回结果数组res。
}
}