
本文详解 two sum 算法在 javascript 中的标准哈希表解法,指出“始终返回空数组”的根本原因——键值存储逻辑颠倒,并提供可直接运行的修正代码及关键注意事项。
本文详解 two sum 算法在 javascript 中的标准哈希表解法,指出“始终返回空数组”的根本原因——键值存储逻辑颠倒,并提供可直接运行的修正代码及关键注意事项。
Two Sum 是算法面试中最基础也最关键的哈希表应用题:给定一个整数数组 nums 和目标值 target,要求返回两个数之和等于 target 的下标(非数值)组成的数组,且每个输入有唯一解。
你提供的原始代码看似结构完整,但核心逻辑存在方向性错误:
// ❌ 错误写法(导致始终返回 []) let comp = target - nums[i]; if (map[comp] !== undefined) { // 检查 complement 是否已存在 → 正确 ✅ return [map[comp], i]; } else { map[comp] = i; // ⚠️ 错误:存的是 complement,而非当前 num! }
问题在于:map[comp] = i 将「补数」作为键、当前索引作为值存入哈希表。这会导致后续遍历时,当遇到真正的 nums[j] === comp 时,map[nums[j]] 实际查的是 map[comp] —— 而此时 comp 并未作为键被存入(除非巧合),因此 map[comp] 始终为 undefined,循环结束返回空数组 []。
✅ 正确逻辑应是:遍历中,以当前数字 num 为键、其索引 i 为值存入哈希表;每次检查 target – num(即补数)是否已在表中存在。若存在,说明之前某次遍历已见过该补数,二者相加即为 target。
立即学习“Java免费学习笔记(深入)”;
以下是修正后的标准实现:
function twoSum(nums, target) { const numsMap = {}; // 哈希表:key = 数值,value = 对应索引 for (let i = 0; i < nums.length; i++) { const num = nums[i]; const complement = target - num; // ✅ 检查补数是否已出现过(即是否在 map 中有对应索引) if (numsMap[complement] !== undefined) { return [numsMap[complement], i]; // 返回:补数的索引 + 当前索引 } // ✅ 存储当前数字及其索引(为后续可能的匹配做准备) numsMap[num] = i; } // 题目保证有解,此处仅作兜底;若需健壮性可抛错 throw new Error("No two sum solution found"); } // 测试用例 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]
? 关键注意事项:
- 不要混淆键与值:哈希表中必须用 num(实际出现的数)作键,而非 target – num;
- 检查时机要前置:必须在存入当前 num 之前检查 complement,否则会错误匹配自身(如 nums = [3], target = 6);
- 避免 map[xxx] == NULL 判定:使用 !== undefined 或 in 操作符更安全,防止 0 或 false 等 falsy 值误判;
- 时间复杂度 O(n),空间复杂度 O(n):单次遍历 + 哈希表查找,是最优解;
- 若题目允许返回任意一组解(而非首次解),本实现天然满足;若需最小索引和等定制逻辑,需额外处理。
掌握这一模式,不仅解决 Two Sum,更为三数之和、四数之和及各类子数组/子序列哈希优化问题奠定坚实基础。