题目内容:
给定一个整数数组 nums
和一个目标值 target
,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
解析:
首先题意在一个数组中找出两个数并且和等于目标值,切不能使用同一个元素(即数组下标相等不可以使用);
第一种解法:暴力解法
两层循环,每次以前一个数为参考,往后遍历每一个数,如果两个数的和等于目标值就返回此时两个数的下标;
时间复杂度:由于需要两层遍历每一层都需要执行n次,所以是O(n^2)
空间复杂度:由于需要的辅助空间就是返回时创建的一个数组且大小为2,所以是O(1)
具体实现代码如下:
public static int[] TwoSum1(int[] nums, int target){
for(int i = 0;i < nums.length - 1; 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 such numbers!");
}
第二种解法:使用两遍HashMap解决
由于暴力解法时间复杂度太大,所以所以可以使用哈希表;但是这需要时额外的空间来存放数组中的数据,这样就是的查找时间降到了O(1),具体实现细节:遍历哈希表,寻找符合target的两个值的下标并返回。
时间复杂度:由于遍历n次,每次在哈希表中查找时间短到了O(1),所以是O(n)
空间复杂度:最多需要存储n个元素在哈希表中,所以是O(n)
具体实现代码如下:
public static int[] TwoSum2(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i); //第一遍将数组中的所有值及其下标放入
}
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i]; //这是将另外一个数计算出
//判断另外一个数是否存在于map中且不等于另一个数
if (map.containsKey(complement) && map.get(complement) != i) {
return new int[]{i,map.get(complement)};
}
}
throw new IllegalArgumentException("No such numbers!");
}
第三种解法:使一遍HashMap
有第二种可知,可以在遍历时将元素添加进哈希表,同时进行元素判断。
时间复杂度和空间复杂度同第二种解法。
具体代码实现如下:
public static int[] TwoSum3(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
//向map中放入数组中的元素,不能在此处就开始放,因为如果数组中有重复的元素,
//存入map中时就覆盖前面已经存储过的元素,而且防止找到下标一样元素,所以每一次都是在
//已经存进哈希表的元素进行查找
int complement = target - nums[i]; //这是将另外一个数计算出
if (map.containsKey(complement)) { //判断另外一个数是否存在于map中且不等于另一个数
return new int[]{map.get(complement),i};
}
map.put(nums[i], i); //将数组中的所有值及其下标放入map
}
throw new IllegalArgumentException("No such numbers!");
}