我是陈皮,一个在互联网 Coding 的 ITer,个人微信公众号「陈皮的JavaLib」关注第一时间阅读最新文章。
题目
给定一个整数数组 nums 和一个整数目标值 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(n^2) ,空间复杂度为 O(1) 。
package com.chenpi.no0001;
import java.util.Arrays;
/**
* @author 陈皮
* @version 1.0
* @description
* @date 2022/3/17
*/
public class No0001TwoSum {
public static void main(String[] args) {
No0001TwoSum inst = new No0001TwoSum();
int[] nums = {1, 2, 6, 4, 10, 11, 8, 9};
int target = 16;
System.out.println(Arrays.toString(inst.twoSum(nums, target)));
}
public int[] twoSum(int[] nums, int target) {
int length = nums.length;
for (int i = 0; i < length - 1; i++) {
for (int j = i + 1; j < length - 1; j++) {
if (nums[i] + nums[j] == target) {
return new int[]{i, j};
}
}
}
return new int[]{};
}
}
// 输出结果如下
[2, 4]
解法二
两数之和,即 A+B=SUM 。在已知 SUM 的情况下,然后又知道 A 的值,那么只需要找到一个数 B 等于 SUM - A 即可。
我们只要遍历一遍数组,遍历过的每一个元素值以及它对应下标值,能通过某种规则或者算法(此规则和算法要简单并且存取速度要快)存储起来。后续我们再去查找这个元素的时候能快速查出来,那算法速度就大大提高了。这样只需要遍历一遍数组即可,时间复杂度为 O(N) 。不仅要存取速度快,还能存储对应的数和下标键值对,那就非哈希表莫属了。
时间复杂度为 O(n) ,空间复杂度为 O(n) 。
算法步骤:
- 遍历数组每一个数 num,通过 target-num 计算出另一个加数 A ;
- 在 map 中查找 key 是否等于 A 的值,如果存在,则返回当前数 num 的下标和 A 的下标;
- 如果不存在,则将此数 num 放入map 中,key 为 num,value 为 num 在数组中的下标;
package com.chenpi.no0001;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @author 陈皮
* @version 1.0
* @description
* @date 2022/3/17
*/
public class No0001TwoSum {
public static void main(String[] args) {
No0001TwoSum inst = new No0001TwoSum();
int[] nums = {1, 2, 6, 4, 10, 11, 8, 9};
int target = 16;
System.out.println(Arrays.toString(inst.twoSum(nums, target)));
}
public int[] twoSum(int[] nums, int target) {
// 记录每一个遍历过的数,利用HashMap插入查找0(1)的高效率时间复杂度
Map<Integer, Integer> indexMap = new HashMap<>(16);
// 遍历每一个数
for (int index = 0; index < nums.length; index++) {
// target-nums[index]算出另一个加数,然后在map中找有没有这个加数
if (indexMap.get(target - nums[index]) != null) {
// 找到了,就返回2个加数的下标
return new int[]{indexMap.get(target - nums[index]), index};
} else {
// 没找到,就将这个数放入map中,key为这个数,value为这个数的下标
indexMap.put(nums[index], index);
}
}
return null;
}
}
// 输出结果如下
[2, 4]
扩展
如果不考虑下标的话,例如只判断是否存在和为目标值的两元素,及其它们的值。其实可以将数组进行排序,然后使用头尾双指针,逐渐靠中间遍历,看是否存在和为目标值的两元素。
遍历一遍数组的时间复杂度为 O(n) ,排序时间复杂度可以为 O(nlogn) ,空间复杂度取决于使用的排序算法。
package com.chenpi.no0001;
import java.util.Arrays;
/**
* @author 陈皮
* @version 1.0
* @description
* @date 2022/3/17
*/
public class No0001TwoSum {
public static void main(String[] args) {
No0001TwoSum inst = new No0001TwoSum();
int[] nums = {1, 2, 6, 4, 10, 11, 8, 9};
int target = 16;
System.out.println(Arrays.toString(inst.twoSum2(nums, target)));
}
// 扩展
public int[] twoSum(int[] nums, int target) {
// 升序
Arrays.sort(nums);
System.out.println(Arrays.toString(nums));
// 双指针指向头尾
int left = 0, right = nums.length - 1;
while (left < right) {
if (nums[left] + nums[right] == target) {
// 满足条件
return new int[]{left, right};
} else if (nums[left] + nums[right] < target) {
// 和比目标值小,左指针向右移,让和增大
left++;
} else {
// 和比目标值大,右指针向左移,让和减小
right--;
}
}
return null;
}
}
// 输出结果如下
[1, 2, 4, 6, 8, 9, 10, 11]
[3, 6]
本次分享到此结束啦~~
如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!