跳到正文
第 1 题简单

两数之和

Two Sum

在数组里找出两个数,使它们的和等于 target,返回这两个数的下标(每个数只能用一次,答案唯一)。

在力扣中练习

题目描述

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。

你可以按任意顺序返回答案。

 

示例 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]

 

提示:

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案

 

进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

解题思路

主解法

哈希表 · 一次遍历

不找「两个数」,改成找「一个数的搭档」

直接两层循环能找答案,但每个数都会反复查找同一批搭档。把已经看过的值与下标存在哈希表里,就能把“之前有没有 target-x”变成一次查询。

自拟主例:nums = [6,-2,5,6,10,1],target = 12,唯一答案是下标 [0,3]。两个 6 数值相同,身份却不同;第一个 6 不能与自己配对。

分步图解

先建立空哈希表。两个 6 是不同下标,不能拿同一个位置用两次。

nums · 先查之前的搭档,再登记自己
0
1
2
3
4
5
6
-2
5
6
10
1
seen · 值 → 之前的下标
{ }
1 / 5
第二个 6 查到第一个 6 的下标,而不是与自己配对。

因此顺序必须是先查搭档,再登记自己。扫描第二个 6 时,表里已经保存 6 → 0,直接返回 [0,3]。表中保存的是下标而不是出现次数,才能还原题目要求的两个位置。查找成功后立即返回,尚未扫描的元素不影响答案。

时间 平均 O(n)空间 O(n)

易错点

  • 先存后查:target = 8、nums = [4, ...] 时会把同一个元素用两次。
  • 返回 {i, j} 顺序反了 —— 本题虽不校验顺序,但按题目习惯返回小下标在前更稳妥。
  • 用 map 而不是 unordered_map,复杂度退化成 O(n log n)。
对照解法

暴力枚举

O(n²) 对照版,用来理解哈希表到底省掉了什么

结果正确,但最坏 O(n²),大输入可能超时;仅用于与哈希表的一次扫描对照。

最直白的想法:枚举所有数对 (i, j),判断 nums[i] + nums[j] == target。

内层循环从 i + 1 开始,天然保证每个元素只被用一次,也不会有重复数对。

它的问题不是「错」,而是「重复劳动」:对每个 i 都要把后面所有元素扫一遍。哈希表把这些扫描结果缓存了下来——这正是 O(n) 和 O(n²) 的差距来源。

数据规模 n ≤ 10⁴ 时暴力也能过,但面试里写出 O(n) 才是加分项。

  1. 1外层 i 从 0 到 n-1。
  2. 2内层 j 从 i+1 到 n-1。
  3. 3若 nums[i] + nums[j] == target,返回 {i, j}。
时间 O(n²)空间 O(1)

易错点

  • 内层从 0 开始会导致同一个元素被用两次。
  • 内层写成 j <= i 会重复检查已经试过的数对。

代码与演示

主解法配有图解;对照解法用于比较思路、复杂度或实现方式。

演示输入nums = [6, -2, 5, 6, 10, 1], target = 12

先建立空哈希表。两个 6 是不同下标,不能拿同一个位置用两次。

nums · 先查之前的搭档,再登记自己
0
1
2
3
4
5
6
-2
5
6
10
1
seen · 值 → 之前的下标
{ }
1 / 5
查看 C++ 代码

延伸阅读

  • 「用空间换时间」是哈希类题目的通用套路:把「我见过什么」记下来,后面的元素就不必回头。
  • 如果题目改成「返回值本身」且数组有序,可以用双指针做到 O(1) 额外空间。
  • 同类变形:三数之和(15)固定一个数后,就退化成本题的双指针版本;和为 K 的子数组(560)把哈希表换成了前缀和。