题目描述

✅ 1. 两数之和

image-20260928184021803

image-20260928184021804

题意分析

在整数数组中找到两个不同位置的元素,使它们的和等于 target,返回这两个位置的下标。需要返回的是下标,不是元素值;两数的值可以相同,但不能重复使用同一个位置。

题目保证恰好有一组答案,返回下标的顺序不限。数组没有排序,并且原始下标需要保留,因此可以在遍历时直接记录出现过的数及其位置。

解法:一次遍历哈希表

核心思路

[!blue]

固定当前元素 nums[i] 后,另一个数必须等于 target - nums[i],称为补数。问题由“枚举所有数对”变成“快速判断需要的补数是否已经出现”,因此用哈希表保存已经遍历过的“数值 → 下标”,用一次查找替代对前面元素的逐个比较。

遍历到位置 i 时,先查补数。如果表中存在它,就得到一组答案:表里的下标来自当前位置之前,必然与 i 不同。查不到才将 nums[i] 和 i 写入表中,等待后面的元素来配对。先查再存,也保证补数恰好等于当前值时不会把当前元素与自己配对。

为什么只查前面的元素就足够?任意一组答案都有先出现和后出现的两个位置;遍历到后者时,前者对应的数值已经被记录,所以这组答案一定会被找到。相同数值再次出现时,可以覆盖旧下标:数值没有改变,保存的位置仍早于后续遍历的位置,因此不会影响之后的合法配对,无需保存所有出现位置。

Java 用查询结果是否为 null 判断补数存在与否,Go 用 map 查询返回的 ok。不能把下标是否为 0 当作存在标记,因为下标 0 本身就是合法答案。题目保证有解,所以找到后可以直接返回,无需继续枚举。

解题步骤

  • 创建空哈希表 indexByValue。
  • 遍历数组,计算补数 need = target - nums[i]。
  • 若补数已在表中,返回补数下标和当前下标。
  • 否则记录当前值及其下标,继续遍历。

代码实现

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> indexByValue = new HashMap<>();

        for (int i = 0; i < nums.length; i++) {
            int need = target - nums[i];
            // 表中只有当前下标之前的元素,命中时不会复用自身。
            Integer j = indexByValue.get(need);

            if (j != null) {
                return new int[] {
                    j,
                    i,
                };
            }

            // 先查补数再记录当前值,两个相同值也能正确配对。
            indexByValue.put(nums[i], i);
        }

        return new int[0];
    }
}
func twoSum(nums []int, target int) []int {
    indexByValue := make(map[int]int)

    for i, num := range nums {
        need := target - num
        // 表中只有当前下标之前的元素,命中时不会复用自身。
        if j, ok := indexByValue[need]; ok {
            return []int{
                j,
                i,
            }
        }
        // 先查补数再记录当前值,两个相同值也能正确配对。
        indexByValue[num] = i
    }

    return []int{}
}

复杂度分析

  • 时间复杂度:平均 $O(n)$,每个元素至多查询、写入哈希表一次,单次哈希表操作平均为 $O(1)$。
  • 空间复杂度:$O(n)$,哈希表最多保存 $n$ 个元素。

关键点总结

[!green]

  • 哈希表保存下标,而不是只记录元素是否存在。
  • 先查补数、后存当前值,既避免复用当前元素,也能正确处理重复值。
  • 命中即返回,无需继续遍历或额外排序。

易错点总结

[!yellow]

  • 先存当前值再查补数,可能把同一元素使用两次。
  • 哈希表只存元素、不存下标,无法构造返回值。
  • 把重复值丢弃后再处理,会漏掉由两个相同数值组成的答案。

相似题目

题目 难度 关联与区别
167. 两数之和 II - 输入有序数组 中等 数组有序后可用两端指针寻找互补值,本题无序时用哈希表记录已见元素。
15. 三数之和 中等 固定一个元素后转成两数之和,额外处理三元组去重。
170. 两数之和 III - 数据结构设计 简单 用哈希表查询当前元素所需的补值;本题查找一个目标和下标对,该题把补值查询扩展为多次动态查询。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/24356627
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!