LeetCode 第一题(两数之和)用哈希表解法的核心是以空间换时间,将查找目标值的时间从 O (n) 降到 O (1),整体时间复杂度 O (n),空间复杂度 O (n)。
核心思路
遍历数组时,用哈希表(对象 / Map) 存储已遍历元素的值:对应索引 ;对当前元素nums[i],计算目标差值target - nums[i],若差值存在于哈希表中,直接返回[哈希表差值的索引, i];若不存在,将当前元素和索引存入哈希表,继续遍历。
可直接运行的 JS 代码(Map 版,推荐)
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
const map = new Map(); // 哈希表:key=数值,value=索引
for (let i = 0; i < nums.length; i++) {
const diff = target - nums[i];
if (map.has(diff)) { // 差值已存在,找到解
return [map.get(diff), i];
}
map.set(nums[i], i); // 未找到,存入当前元素
}
return []; // 题目保证有解,此句可省略
};
简化版(对象版)
var twoSum = function(nums, target) {
const obj = {};
for (let i = 0; i < nums.length; i++) {
const diff = target - nums[i];
if (diff in obj) {
return [obj[diff], i];
}
obj[nums[i]] = i;
}
};
关键细节
- 为什么不用先存全部元素 :边遍历边存,避免同一元素被重复使用(如
target=6,nums=[3,3],先查再存可正确匹配两个 3); - Map vs 普通对象:Map 支持任意类型键,且不会与对象原型属性冲突,处理负数 / 0 更安全,推荐使用;
- 题目特性 :题目明确有且仅有一个解,无需处理多解 / 无解情况,遍历到解可直接返回。
对比暴力解法
| 解法 | 时间复杂度 | 空间复杂度 | 核心逻辑 |
|---|---|---|---|
| 暴力双重 for | O(n²) | O(1) | 遍历所有元素两两组合 |
| 哈希表法 | O(n) | O(n) | 哈希表快速查找目标差值 |
两数之和(哈希解法)核心边界测试用例
覆盖重复元素、负数、目标值为 0、单元素相邻匹配四大高频边界,附测试结果 + 代码适配性说明(上述 Map / 对象解法均完美适配)
1. 重复元素(核心易错题)
- 用例:
nums = [3,3], target = 6 - 结果:
[0,1] - 关键:边查边存 ,先判断
diff=3是否在哈希表(初始空),再存入第一个 3,遍历第二个 3 时可匹配到第一个 3 的索引,避免同一元素重复使用。
2. 包含负数
- 用例:
nums = [2,7,-1,15], target = 6 - 结果:
[2,3] - 关键:Map / 对象对负数键无处理问题,比数组下标法更适配负数场景。
3. 目标值为 0
- 用例:
nums = [-1,0,1,2], target = 0 - 结果:
[0,2] - 关键:哈希表可正常存储 / 查找
0和负数值,无特殊处理逻辑。
4. 相邻元素匹配(基础边界)
- 用例:
nums = [2,7,11,15], target = 9 - 结果:
[0,1] - 关键:遍历第二个元素 7 时,
diff=2已在哈希表中,直接返回结果,是最基础的正常场景。
5. 元素为 0 的重复匹配
- 用例:
nums = [0,4,0,3], target = 0 - 结果:
[0,2] - 关键:哈希表按首次出现存储索引,后续匹配可精准拿到前置索引。
测试代码(可直接运行)
将上述用例代入解法,快速验证结果:
var twoSum = function(nums, target) {
const map = new Map();
for (let i = 0; i < nums.length; i++) {
const diff = target - nums[i];
if (map.has(diff)) return [map.get(diff), i];
map.set(nums[i], i);
}
return [];
};
// 测试用例执行
console.log(twoSum([3,3],6)); // [0,1]
console.log(twoSum([2,7,-1,15],6)); // [2,3]
console.log(twoSum([-1,0,1,2],0)); // [0,2]
console.log(twoSum([2,7,11,15],9)); // [0,1]
console.log(twoSum([0,4,0,3],0)); // [0,2]
边界坑点总结
-
若先存后查 ,会导致重复元素用例失败(如
[3,3]会匹配到同一索引); -
用普通对象时,若数值为
__proto__(极端情况)会冲突,Map 可彻底避免,推荐优先使用; -
无需处理数组长度 < 2 的情况,题目明确有且仅有一个解,输入均为有效用例。
const map = new Map();
map.set('a', 5);
map.set('b', 7);
map.set('c', 9);console.log(map.get('a')); // 5
console.log(map.has('b')); // true
