难度:Easy
题目描述:
给定一个数组,输出两个元素之和等于指定数字的下标,同一个元素不能使用两次。
例如:
Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].
这道题给了我们一个数组,还有一个目标数target,让找到两个数字,使其和为 target,乍一看就感觉可以用暴力搜索,但是猜到 OJ 肯定不会允许用暴力搜索这么简单的方法,于是去试了一下,果然是 Time Limit Exceeded,这个算法的时间复杂度是 O(n^2)。那么只能想个 O(n) 的算法来实现,由于暴力搜索的方法是遍历所有的两个数字的组合,然后算其和,这样虽然节省了空间,但是时间复杂度高。一般来说,为了提高时间的复杂度,需要用空间来换,这算是一个 trade off 吧,但这里只想用线性的时间复杂度来解决问题,就是说只能遍历一个数字,那么另一个数字呢,可以事先将其存储起来,使用一个 HashMap,来建立数字和其坐标位置之间的映射,由于 HashMap 是常数级的查找效率,这样在遍历数组的时候,用 target 减去遍历到的数字,就是另一个需要的数字了,直接在 HashMap 中查找其是否存在即可,注意要判断查找到的数字不是第一个数字,比如 target 是4,遍历到了一个2,那么另外一个2不能是之前那个2,整个实现步骤为:先遍历一遍数组,建立 HashMap 映射,然后再遍历一遍,开始查找,找到则记录 index。或者可以写的更加简洁一些,把两个 for 循环合并成一个
解决方案:
1、暴力遍历数组:
public static int[] twoSum(int[] nums, int target) {
int[] a = new int[2];
if (nums == null) {
return null;
}
int n = nums.length;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (nums[i] + nums[j] == target) {
a[0] = i;
a[1] = j;
}
}
}
return a;
}
时间复杂度:O(n^2)
空间复杂度:O(1)
2、使用HashMap,nums数组元素为key,下标为value
public static int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[] { map.get(complement), i };
}
map.put(nums[i], i);
}
return null;
}
时间复杂度:O(n)
空间复杂度:O(n)