1. 两数之和
1、题目
题目要求
给定一个整数数组 nums
和一个目标值 target
,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15]
, target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
,所以返回 [0, 1]
2、参考资料
- https://leetcode-cn.com/problems/two-sum/solution/liang-shu-zhi-he-by-leetcode-2/
3、代码思路
为了对运行时间复杂度进行优化,我们需要一种更有效的方法来检查数组中是否存在目标元素。如果存在,我们需要找出它的索引。保持数组中的每个元素与其索引相互对应的最好方法是什么?哈希表。
通过以空间换取速度的方式,我们可以将查找时间从 O(n) 降低到 O(1)。哈希表正是为此目的而构建的,它支持以 近似 恒定的时间进行快速查找。我用“近似”来描述,是因为一旦出现冲突,查找用时可能会退化到 O(n)。但只要你仔细地挑选哈希函数,在哈希表中进行查找的用时应当被摊销为 O(1)。
使用了两次迭代即可完成上述操作
- 在第一次迭代中,我们将每个元素的值和它的索引添加到表中
- 然后,在第二次迭代中,我们将检查每个元素所对应的目标元素(
target - nums[i]
)是否存在于表中。注意,该目标元素不能是nums[i]
本身! - 在
HashMap
中,以数组元素值为key
,数组元素索引为value
,如果从HashMap
中get()
到的值不为null
,并且两个数的索引不同(不是nums[i]
本身),则说明两数之和等于target
,返回这两个数在数组中的索引即可
4、代码实现
代码实现
代码
public static void main(String[] args) {
int[] destNums = twoSum(new int[] { 2, 7, 11, 15 }, 9);
System.out.println(Arrays.toString(destNums));
}
public static int[] twoSum(int[] arr, int target) {
// 巧用哈希表
Map<Integer, Integer> map = new HashMap<>();
// 将数组元素添加至 map ,以数组元素值为 key ,数组元素索引为 value
for (int i = 0; i < arr.length; i++) {
map.put(arr[i], i);
}
// 从 map 取出 (target - arr[i])
for (int i = 0; i < arr.length; i++) {
// 获取数组元素下标
Integer j = map.get(target - arr[i]);
// 如果能获取到,说明 (arr[i] + arr[j]) == target ,并且不能是其本身
if (j != null && j != i) {
return new int[] { i, j };
}
}
return null;
}
复杂度分析:
- 时间复杂度:O(n),我们把包含有
n
个元素的列表遍历两次。由于哈希表将查找时间缩短到 O(1),所以时间复杂度为 O(n)。 - 空间复杂度:O(n),所需的额外空间取决于哈希表中存储的元素数量,该表中存储了
n
个元素。
代码优化
程序优化:事实证明,我们可以一次完成。在进行迭代并将元素插入到表中的同时,我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在,那我们已经找到了对应解,并立即将其返回。
public static void main(String[] args) {
int[] destNums = twoSum(new int[] { 2, 7, 11, 15 }, 26);
System.out.println(Arrays.toString(destNums));
}
public static int[] twoSum(int[] arr, int target) {
// 巧用哈希表
Map<Integer, Integer> map = new HashMap<>();
// 将数组元素添加至 map ,以数组元素值为 key ,数组元素索引为 value
for (int i = 0; i < arr.length; i++) {
map.put(arr[i], i);
// 获取数组元素下标
Integer j = map.get(target - arr[i]);
// 如果能获取到,说明 (arr[i] + arr[j]) == target
if (j != null && j != i) {
return new int[] { i, j };
}
}
return null;
}
- 程序运行结果
[2, 7]
复杂度分析:
时间复杂度:O(n),我们只遍历了包含有 n
个元素的列表一次。在表中进行的每次查找只花费 O(1) 的时间。
空间复杂度:O(n),所需的额外空间取决于哈希表中存储的元素数量,该表最多需要存储 n
个元素。