给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
分析
最简单的想法就是把每两个都拿出来加一下,看看结果是不是我们想要的。但是直觉告诉我们,这样子并不高效。举一个很实际的例子就能明白。
比如这个周末你去参加线下相亲会,全场有且只有两个人才是真爱。于是我们每个人都要去找其他所有人聊天,去寻找 ta 是不是自己要找的另一半。每个人都要和每个人说话,这样时间复杂度很高,翻译成计算机的表示就是 O(n2)。
JavaScript
var twoSum = function(nums, target) {
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 [nums[i], nums[j]]
}
}
}
}
怎么样可以更高效一点?
这时候要引入哈希表,其实就是一个登记册,写上你的名字和你的要求。如果每个人都提前在主持人那里登记一遍,然后只要大家依次再报出自己名字,主持人就能够识别到,ta 就是你要找的人。
JavaScript
var twoSum = function(nums, target) {
let res = {}
for (let i = 0; i < nums.length; i++) { // 每个人登记自己想要配对的人,让主持人记住
res[target - nums[i]] = nums[i]
}
for (let j = 0; j < nums.length; j++) { // 每个人再次报数的时候,主持人看一下名单里有没有他
if (res[nums[j]] !== undefined) {
return [nums[j], res[nums[j]]]
}
}
}
很容易看出来,上面的方案仍然可以优化。就是每个人都来问一下主持人,自己要找的人有没有来登记过,如果没有的话,就把自己的要求写下来,等着别人来找自己。
JavaScript
var twoSum = function(nums, target) {
let res = {}
for (let i = 0; i < nums.length; i++) { // 每个人报出自己想要配对的人
if (res[nums[i]] !== undefined) { // 如果有人被登记过
return [nums[i], res[nums[i]]] // 就是他
} else { // 否则
res[target - nums[i]] = nums[i] // 主持人记住他的需求
}
}
}
2sum 问题最坏的情况是,第一个人和最后一个人配对,每个人都发了一次言。时间复杂度是 O(n),空间复杂度也是 O(n),因为主持人要用小本本记录下每个人的发言,最坏的时候,要把所有人的诉求都记一遍。
链接
java 代码
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> map = new HashMap<>(nums.length);
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(target - nums[i]) && map.get(target - nums[i]) != i) {
return new int[]{i, map.get(target - nums[i])};
}
}
return null;
}