🎯 LeetCode 1 | 两数之和(Two Sum)
“两数之和”的双指针解法和哈希解法,以双指针为主。
🔍 问题描述
给定一个整数数组 nums
和一个整数目标值 target
,请你从该数组中找出 和为目标值的两个不同元素,并返回它们的下标。
你可以假设:
- 每种输入只会对应一个有效答案;
- 不能使用同一个元素两次;
- 可以按任意顺序返回答案。
🔗 原题链接:LeetCode 1. 两数之和
🌈 示例 & 输出说明
📌 示例 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]
💡 解题思路
✨ 方法一:排序 + 双指针法
思路简述:
- 创建一个二维数组
indexNums
,记录每个元素的值及其原始索引; - 对这个数组按照数值进行排序;
- 使用双指针分别从头(left)和尾(right)遍历数组,寻找和为
target
的两个数; - 如果找到,则返回其对应的原始索引;
- 注意不能使用相同的元素(即不能
left == right
);
优势分析:
- 排序后利用双指针可以快速查找;
- 时间复杂度为 O(n log n),优于暴力枚举的 O(n²);
- 同时保留原索引信息,方便最终结果返回。
✨ 方法二:哈希法
思路简述:
判断一个元素是否出现在一个集合中,用哈希,哈希的键为元素
思路:遍历数组nums 判断target-nums[cur]是否在哈希表内,若在返回cur 和target-nums[cur]对应的索引
如何构造哈希:不在哈希表内,则把nums[i]作为k,i作为v存入哈希内
✅ 示例代码(Java 实现)
方法一:排序 + 双指针法
import java.util.Arrays;
class Solution {
public int[] twoSum(int[] nums, int target) {
// 记录值及对应的原始索引
int[][] indexNums = new int[nums.length][2];
for (int i = 0; i < nums.length; i++) {
indexNums[i][0] = nums[i]; // 存值
indexNums[i][1] = i; // 存索引
}
// 按照数值升序排序
Arrays.sort(indexNums, (a, b) -> a[0] - b[0]);
int left = 0;
int right = nums.length - 1;
while (left < right) {
int sum = indexNums[left][0] + indexNums[right][0];
if (sum < target) {
left++;
} else if (sum > target) {
right--;
} else {
return new int[]{indexNums[left][1], indexNums[right][1]};
}
}
// 理论上不会走到这里
throw new IllegalArgumentException("No two sum solution");
}
}
方法二:哈希法
class Solution {
//使用哈希表
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
if(nums == null || nums.length == 0){
return res;
}
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i++){
int temp = target - nums[i]; // 遍历当前元素,并在map中寻找是否有匹配的key
if(map.containsKey(temp)){
res[1] = i;
res[0] = map.get(temp);
break;
}
map.put(nums[i], i); // 如果没找到匹配对,就把访问过的元素和下标加入到map中
}
return res;
}
}
🧩 小贴士(Tips)
⚠️ 注意事项
- 不能使用相同的元素:比如
nums = [3, 2, 4]
,如果target = 6
,虽然nums[0] + nums[0] == 6
,但这是不允许的。 - 不能修改原数组:保存原始索引非常重要,因为排序会打乱顺序;
- 异常处理:建议在找不到解时抛出异常,而不是直接返回空数组;
- 效率优化:排序加双指针的时间复杂度是 O(n log n),适用于大多数场景。
📊 复杂度分析
操作 | 时间复杂度 | 空间复杂度 |
---|---|---|
排序 | O(n log n) | O(n) |
双指针查找 | O(n) | O(1) |
总体 | O(n log n) | O(n) |
🎯 总结
本题的关键在于:
- 掌握排序 + 双指针的技巧;
- 理解索引保存的重要性;
- 注意不能使用相同元素;
- 学会异常处理和边界判断;
🚀 拓展思考
- 能否用哈希表实现?时间复杂度可优化到 O(n),空间换时间的经典案例。
- 如何将“两数之和”扩展为“三数之和”或“四数之和”?
- 若允许重复使用相同元素如何处理?
📖 相关推荐
💬 互动一下:
你第一次做“两数之和”这道题时遇到什么挑战了吗?欢迎留言分享你的经历👇