题目描述
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
2 <= nums.length <= 10^4
-10^9 <= nums[i] <= 10^9
-10^9 <= target <= 10^9
- 只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2)
的算法吗?
题解
方法一:暴力循环
时空复杂度: O(n^2) O(1)
这个方法大家应该都已经司空见惯了吧,直接暴力两重for循环,十分暴力,直接去找target - nums[i]这个数字,找到直接返回即可。这题的数据就算执行暴力循环也就是 O(10^8) 的时间复杂度,没有超时。
public int[] brustMethod(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};
}
}
}
}
方法二:排序+双指针
时空复杂度: O(nlogn) O(n)
本人想到的第二种方法是使用排序加双指针,用空间换时间嘛,具体思路就是先存所有元素和下标关系到map中。然后对数组进行排序,用左端点和右端点的指针向中间逼近,当左指针指向的元素小于target就让左指针右移动,反之则让右指针左移。最终会找到两个目标元素。
public int[] sortAndDualMethod(int[] nums,int target){
//构建下标和元素值之间的关系,这里我们value使用List列表是因为可能两个元素相等。
//题目已经告诉我们了只有一个答案,所以不会出现一个元素和另一个出现两次的元素中的一个元素作为答案的情况
Map<Integer,List<Integer>> map = new HashMap();
for(int i = 0; i < nums.length; i ++) {
//获取元素对应的下标列表
List<Integer> list = map.getOrDefault(nums[i],new ArrayList<Integer>());
//将下标插入列表中
list.add(i);
//存回map中
map.put(nums[i],list);
}
//排序数组
Arrays.sort(nums);
//双指针查找
int l = 0,r = nums.length - 1;
int sum = nums[l] + nums[r];
while(sum != target) {
if(sum > target) {
r --;
} else if(sum < target) {
l ++;
}
sum = nums[l] + nums[r];
}
//当找到结果的时候
//如果是两个相同元素
if(nums[l] == nums[r]) {
int[] res = new int[2];
res[0] = map.get(nums[l]).get(0);
res[1] = map.get(nums[l]).get(1);
return res;
} else {
//两个元素不同
return new int[]{map.get(nums[l]).get(0),map.get(nums[r]).get(0)};
}
}
方法三:哈希表
时空复杂度:O(n) O(n)
这种方法自认为是最优秀的,时间复杂度和空间复杂度都取决于结果元素出现在数组中的位置,最坏为O(n),最好为O(2),是十分优秀的了
public int[] hashMethod(int[] nums,int target) {
//创建hash表
Map<Integer,Integer> map = new HashMap();
//这里存入哈希表的时候是依照数组顺序,所以无需考虑重复元素的问题。
for(int i = 0; i < nums.length; i ++) {
if(map.containsKey(target - nums[i])) {
return new int[]{i,map.get(target - nums[i])};
}
//如果哈希表中不存在这个元素就加入当前元素到哈希表,并且继续遍历
map.put(nums[i],i);
}
return null;
}
总结
有人相爱,有人夜里开车看海,有人LeetCode第一题都做不出来。(手动狗头)
这道题目还是考察我们对于哈希表的应用。当然我们也可以使用暴力算法,也是可以通过这道题目的,我们可以逐步优化自己的方法。
本人刚开始写的时候也是使用O(n^2)的复杂度,后面想到使用双指针加排序,优化到了O(nlogn),最后使用哈希表优化到了O(n)。我们要经历自己去优化方法的过程,这个过程还是比较锻炼我们的编程思维的。