给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]
解法1:暴力求解
class Solution {
public int[] twoSum(int[] nums, int target) {
for (int i = 0;i < nums.length;i++){
for (int j = i + 1;j < nums.length;j++){
if (nums[i] + nums[j] == target){
return new int[]{i,j};
}
}
}
throw new IllegalArgumentException("No two sum solution");
}
}
解法2:利用HashMap
- 解法1的问题是,我们最后要的答案是数组的下标,而在数组中我们只能通过下标访问到元素。
- 如果我们只能通过下标访问到元素,我们需要对每对可能出现的值对组合进行遍历,那么最后时间复杂度必然是O(n^2)
- 而如果我们可以通过元素访问下标,遍历一遍数组,对于每个元素,都只需要进行一个操作:在已检查过的元素里查询是否有符合条件的元素,找到则返回它的下标
换句话说,这道题的思路其实只有一种:对每一个数组中的元素,查询某条件下的另一元素的下标
第一个循环,两种方法是一致的,所以至少O(n)
数组:我知道我有一堆元素,我不知道他们是啥。查询的思路孜然是再遍历一次之前的数组元素,找到目标元素。
HashMap:我知道我有什么元素。那么我既然知道你要找的数组元素大小是多少,直接查看键值对里有没有这个键就好了。
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
int i;
int complement;
for (i = 0;i < nums.length;i++){
complement = target - nums[i];
if(map.containsKey(complement)){
return new int[] {map.get(complement), i};
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("!!!");
}
}
这道题的目的在于,告诉我们有一种数据结构(Map)可以实现两种结构间的一对一访问,而其中的佼佼者,叫做HashMap(用TreeMap试验了一下,速度比HashMap慢,时间复杂度应该是O(nlogn))