题目链接: https://leetcode.cn/problems/two-sum/
视频题解: https://b23.tv/g6f8fCg
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
举个例子:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
首先暴力的方法就不说了,比较简单但是时间复杂度比较高。这里讲一种空间换时间的方法,利用hash
表,提前把nums
中的元素nums[i]
作为hash
表的key
主键,nums
的索引作为hash
表的value
值存到hash
表中。
这样我们只需要遍历nums
,在hash
表中寻找target-nums[i]
,如果target-nums
存在hash
表中,且hash[target-nums] != i
,那么就返回{i,hash[target-nums]}
。如果遍历完整个nums
都没有任何结果返回,就说明没有找到。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> u_map;
int nums_len = nums.size();
//预先生成hash表
for (int i = 0; i < nums_len; ++i) {
u_map[nums[i]] = i;
}
for (int i = 0; i < nums_len; ++i) {
//查询由nums所有元素生成的hash表
if(u_map.find(target-nums[i]) != u_map.end() && u_map[target-nums[i]] != i) {
return {i, u_map[target-nums[i]]};
}
}
return {};
}
};
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> u_map = new HashMap<>();
int nums_len = nums.length;
// 预先生成哈希表
for (int i = 0; i < nums_len; i++) {
u_map.put(nums[i], i);
}
for (int i = 0; i < nums_len; i++) {
// 查询由nums所有元素生成的哈希表
if (u_map.containsKey(target - nums[i]) && u_map.get(target - nums[i]) != i) {
return new int[]{i, u_map.get(target - nums[i])};
}
}
return new int[]{};
}
}
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
u_map = {}
nums_len = len(nums)
# 预先生成哈希表
for i in range(nums_len):
u_map[nums[i]] = i
for i in range(nums_len):
# 查询由nums所有元素生成的哈希表
if target - nums[i] in u_map and u_map[target - nums[i]] != i:
return [i, u_map[target - nums[i]]]
return []
上面的方法我们需要预先生成hash
表,这样就会遍历两次nums
,那么能否只遍历一遍nums
呢?对于nums[i]
,我们只需要把每次查询由nums
中所有元素组成的hash
表,修改为每次查询由nums[0]~nums[i-1]
组成的hash
表,其实效果是一样的。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> pre_map;
int nums_len = nums.size();
for (int i = 0; i < nums_len; ++i) {
//查询由nums[0]~nums[i-1]组成的hash表
if(pre_map.find(target-nums[i]) != pre_map.end()) {
return {pre_map[target-nums[i]], i};
} else {
//把当前nums[i]放入hash表
pre_map[nums[i]] = i;
}
}
return {};
}
};
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> preMap = new HashMap<>();
int numsLen = nums.length;
for (int i = 0; i < numsLen; i++) {
// 查询由nums[0]~nums[i-1]组成的哈希表
if (preMap.containsKey(target - nums[i])) {
return new int[]{preMap.get(target - nums[i]), i};
} else {
// 把当前nums[i]放入哈希表
preMap.put(nums[i], i);
}
}
return new int[]{};
}
}
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
pre_map = {}
nums_len = len(nums)
for i in range(nums_len):
# 查询由nums[0]~nums[i-1]组成的哈希表
if target - nums[i] in pre_map:
return [pre_map[target - nums[i]], i]
else:
# 把当前nums[i]放入哈希表
pre_map[nums[i]] = i
return []
时间复杂度: 只需要遍历一遍nums
,每次查hash
表的时间复杂度是O(1),故整体的时间复杂是O(n),其中n
为nums
的长度。
空间复杂度: 需要借用一个hash
表,其大小为n
,n
为nums
的长度,所以空间复杂度为O(n)。