今天给大家分享一道LeetCode上的经典题目------两数之和。这道题是很多人的LeetCode入门题,虽然简单,但蕴含着重要的算法思想。
题目描述
题目链接:
给定一个整数数组 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 <= 104-109 <= nums[i] <= 109-109 <= target <= 109- 只会存在一个有效答案
方法一:暴力枚举(不推荐)
最直观的方法是使用两层循环遍历所有可能的两个数的组合,检查它们的和是否等于target。
时间复杂度 :O(n²)
空间复杂度:O(1)
java
class Solution {
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[i] + nums[j] == target) {
return new int[]{i, j};
}
}
}
return new int[]{};
}
}
方法二:哈希表(最优解)
利用哈希表将查找时间从O(n)降到O(1)。遍历数组时,对于每个元素nums[i],计算target - nums[i]的值,然后在哈希表中查找这个值是否存在。
核心思想:用空间换时间
时间复杂度 :O(n)
空间复杂度:O(n)
代码实现(哈希表法)
java
class Solution {
public int[] twoSum(int[] nums, int target) {
//判断一下是否为空,如果为空则返回空数组
if (nums==null || nums.length==0){
return new int[]{};
}
//创建一个map
Map<Integer,Integer> map=new HashMap<>();
for (int i = 0; i < nums.length; i++){
// 获取当前值
int temp=target-nums[i];
if (map.containsKey(temp)){
return new int[]{map.get(temp), i};
}else {
// 如果没有将当前值放入map中
map.put(nums[i],i);
}
}
// 如果没有找到则返回空数组
return new int[]{};
}
}
代码详解
让我们通过一个例子来理解代码的执行过程:
输入:nums = [2,7,11,15], target = 9
| 步骤 | i | nums[i] | complement | map内容 | 是否找到 |
|---|---|---|---|---|---|
| 1 | 0 | 2 | 7 | {2:0} | 否 |
| 2 | 1 | 7 | 2 | {2:0} | 是 → 返回[0,1] |
复杂度分析
-
时间复杂度:O(n)
-
我们只遍历了一次数组
-
哈希表的查找和插入操作的时间复杂度都是O(1)
-
-
空间复杂度:O(n)
- 最坏情况下,哈希表中需要存储n-1个元素
总结
-
暴力法简单但效率低,面试中通常不会作为最终答案
-
哈希表法是最优解,体现了"空间换时间"的思想
-
关键点:一边遍历一边存,而不是先全部存进去
-
注意事项:边界条件判断、空指针处理
这道题虽然简单,但它是很多复杂问题的基础,比如三数之和、四数之和等。掌握好这道题,对后续的学习很有帮助。