
本文详解 two sum 算法在 javascript 中的标准哈希表解法,指出原实现中“将补数存入 map 而非原数”这一关键错误,并提供可直接运行的修正代码及原理说明。
本文详解 two sum 算法在 javascript 中的标准哈希表解法,指出原实现中“将补数存入 map 而非原数”这一关键错误,并提供可直接运行的修正代码及原理说明。
Two Sum 是算法面试中最基础也最具代表性的哈希表应用题:给定一个整数数组 nums 和目标值 target,要求返回两个不同下标,使得对应元素之和等于 target。高效解法的时间复杂度应为 O(n),核心在于一次遍历 + 哈希表记录已访问元素的值与索引。
原代码的问题根源在于逻辑倒置:
let comp = target - nums[i];
if (map[comp] !== undefined) { // ✅ 正确:检查补数是否已出现过
return [map[comp], i];
} else {
map[comp] = i; // ❌ 错误:此处存的是补数,而非当前数字!
}这导致哈希表中存储的是“期望被匹配的值”,而非“实际已存在的值”。当后续遇到某个数 x 时,我们本应查 target - x 是否已在表中——但此时表里存的却是之前每个数对应的补数,语义错位,匹配必然失败(除非巧合),最终几乎总是返回空数组 []。
✅ 正确做法是:遍历中将当前数字 nums[i] 及其索引 i 存入哈希表;对每个新数字,检查它的补数 target - nums[i] 是否已存在于表中。这样,哈希表始终表示“哪些数字我已经见过”,查询逻辑自然成立。
立即学习“Java免费学习笔记(深入)”;
以下是修正后的完整实现:
function twoSum(nums, target) {
const numsMap = {}; // 键:数字;值:首次出现的索引
for (let i = 0; i < nums.length; i++) {
const num = nums[i];
const complement = target - num;
// 若补数此前已出现,则立即返回两个索引
if (numsMap[complement] !== undefined) {
return [numsMap[complement], i];
}
// 将当前数字及其索引存入哈希表,供后续元素匹配
numsMap[num] = i;
}
return []; // 无解时返回空数组(符合题目契约)
}
// 测试用例
console.log(twoSum([2, 7, 11, 15], 9)); // [0, 1]
console.log(twoSum([3, 2, 4], 6)); // [1, 2]
console.log(twoSum([3, 3], 6)); // [0, 1]? 关键注意事项:
- 索引顺序:返回 [numsMap[complement], i],确保第一个索引小于第二个(因 complement 出现在 i 之前);
- undefined 检查:使用 !== undefined 而非 != null 或 !numsMap[complement],避免 0 索引被误判为假值;
- 重复数字处理:该实现天然支持重复值(如 [3,3]),因哈希表会覆盖同键的旧索引,而首次匹配即终止,故总返回合法解;
- 边界情况:空数组、单元素、无解数组均能正确返回 []。
总结:Two Sum 的哈希解法本质是“边走边记,以待后验”。牢记「存当前数,查补数」八字口诀,即可规避绝大多数实现陷阱。此模式也是三数之和、四数之和等进阶问题的基石。










