#1 哈希表 简单

两数之和

在 LeetCode 上查看 ↗

🎧 语音讲解

开车或通勤时可听,跟着思路走一遍

速度

📋 题目描述

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案,且同一个元素不能使用两遍。

示例 1

输入:nums = [2,7,11,15], target = 9
输出:[0,1](因为 nums[0] + nums[1] == 9)

示例 2

输入:nums = [3,2,4], target = 6
输出:[1,2]

💭 模拟答题者思考

1. 暴力:双重循环枚举所有 (i, j) 看和是否为 target,O(n²)。

2. 重复在哪?对每个 x 都在「重新遍历」找 target - x,其实只要知道它之前是否出现过。

3. 把「找另一半」变成查表:用哈希表存已扫过的值到下标,查找变 O(1)。

4. 边扫边存:先查 target - x 是否在表里,再把 x 存入,保证不会用到自己。

🧠 变量语义(先读这三句再编码)

变量类型语义(三句法)
seenmap<int,int>定义:已扫描过的「值 → 下标」映射
维护:每轮结束后,seen 里存着 nums[0..i] 每个值最后出现的下标
更新:处理完 nums[i] 后 seen[nums[i]] = i
target - xint定义:当前元素 x 需要的「另一半」
维护:随 x 变化
更新:每轮用它去 seen 里查是否出现过

⌨️ 落码步骤

1. 初始化空哈希表 seen

2. 遍历数组,对每个 x = nums[i]:先查 target - x 是否在 seen 中

3. 若在,返回 [seen[target-x], i]

4. 否则把 seen[x] = i 记入历史

💻 代码实现

class Solution:
    def twoSum(self, nums: list[int], target: int) -> list[int]:
        seen = {}  # 值 -> 下标
        for i, x in enumerate(nums):
            if target - x in seen:
                return [seen[target - x], i]
            seen[x] = i
        return []
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> seen;  // 值 -> 下标
        for (int i = 0; i < nums.size(); i++) {
            auto it = seen.find(target - nums[i]);
            if (it != seen.end()) return {it->second, i};
            seen[nums[i]] = i;
        }
        return {};
    }
};
// 时间 O(n),空间 O(n)

📈 复杂度分析

时间复杂度 O(n)
空间复杂度 O(n)

⚠️ 常见坑

必须「先查后存」:如果先把 x 存进表再查,可能会把自己当成另一半(当 target = 2*x 时)。

返回的是下标不是值;题目保证恰有一个答案,无需继续遍历。

有重复值时哈希表会覆盖旧下标,但因为答案唯一,不影响正确性。

🔍 必测边界 Case

Case 1:包含负数
nums = [-3,4,3,90], target = 0 → [0,2]
Case 2:两个相同值
nums = [3,3], target = 6 → [0,1]