两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
例子:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
方法1: 暴力法
暴力法,遍历每个元素
x
x
x,并查找是否有一个值与
t
a
r
g
e
t
−
x
target-x
target−x 相等的目标元素。
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[j] == target - nums[i]) {
return new int[] { i, j };
}
}
}
throw new IllegalArgumentException("No two sum solution");
}
方法2:使用hash表,通过元素的值来快速找到目标元素,以空间换取时间。
一个简单的实现是使用两次迭代。在第一次迭代中,将每个元素的值和它的索引添加到表中;在第二次迭代中,检查每个元素对应的目标元素
t
a
r
g
e
t
−
n
u
m
[
i
]
target-num[i]
target−num[i] 是否存在于表中。注意,该目标元素不能是
n
u
m
[
i
]
num[i]
num[i] 本身。
public int[] twoSum(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];
if (map.containsKey(complement) && map.get(complement) != i) {
return new int[] { i, map.get(complement) };
}
}
throw new IllegalArgumentException("No two sum solution");
}
方法3:一遍hash表
在进行第一次迭代并将元素插入到表中的同时检查表中是否已经存在当前元素对应的目标元素。
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
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);
}
throw new IllegalArgumentException("No two sum solution");
}
扩展问题
- 三数之和:给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
- 四数之和:给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
- 和为 k k k的子数组:给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。