LeeetCode题目网址:https://leetcodechina.com/problems/two-sum/description/
给定一个整数数列,找出其中和为特定值的那两个数。
你可以假设每个输入都只会有一种答案,同样的元素不能被重用。
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
https://github.com/biezhihua/LeetCode
仔细的阅读题目获取有效信息。
思路1:
先确定两数中的一个数,再去确定另外一个数,然后判断两数之和与Target的关系。该解法需要两层for
循环,第一个for
循环用于确定第一个数,第二个for
循环用于确定第二个数,然后在最内部做逻辑判断。
虽然此法简单,但是时间复杂度是 O(n2) O ( n 2 ) 。显然不是最优解法。(谁都能直接想到的解法往往都不是最优解法)。
思路2:
在思路1中“先确定一个数再确定另一个数”显然不是我们继续思考的方向了,因为一次for
能确定一个数和索引,那么能不能在确定索引的同时确定另外一个数的索引呢?也就是如何同时表示两个维度的信息(也就是两个数的信息)。
哈希表 - Map可以同时存储两种信息,并让其对应起来。
数组也可以看做一个哈希表,其索引和数值一一对应,a[i] = value;
我们可以在Map中将当前数与Target值得差值作为Key,将当前数的索引作为Value。这样就同时表示了两个维度的信息,Key代表我们对另外一个数的要求,Value代表当前数的索引。
举个例子,Target为9,当前索引为0数为2,那么差值为7。只要后面数组中存在数值为7,那么两者和就为Target。
该思路的核心在于如何在一次操作中确定两个数的信息。这样遍历一遍就能得到结果,其时间复杂度为 O(n) O ( n ) 。
public class Code_3_4_TwoSum {
@Test
public void test() {
int[] nums = new int[]{2, 7, 11, 15};
Assert.assertArrayEquals(new int[]{0, 1}, twoSum(nums, 9));
Assert.assertArrayEquals(new int[]{-1, -1}, twoSum(nums, 10));
}
int[] twoSum(int[] nums, int target) {
int[] rs = new int[]{-1, -1};
if (nums == null || nums.length <= 1)
return rs;
Map hashMap = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (hashMap.containsKey(nums[i])) {
rs[0] = hashMap.get(nums[i]);
rs[1] = i;
return rs;
} else {
hashMap.put(target - nums[i], i);
}
}
return rs;
}
}