LeetCode 热题 100 - 第 1 题

3 阅读4分钟

LeetCode 热题 100 第 1 题:两数之和(Java 多解法,复习版)

题目链接:leetcode.cn/problems/tw…


一、题目描述

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

说明:

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

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

示例:

  • 示例 1:输入:nums = [2,7,11,15], target = 9 → 输出:[0,1](解释:nums[0] + nums[1] = 2 + 7 = 9)

  • 示例 2:输入:nums = [3,2,4], target = 6 → 输出:[1,2](解释:nums[1] + nums[2] = 2 + 4 = 6)

  • 示例 3:输入:nums = [3,3], target = 6 → 输出:[0,1](解释:nums[0] + nums[1] = 3 + 3 = 6)

提示:

  • 2 ≤ nums.length ≤ 10⁴

  • -10⁹ ≤ nums[i] ≤ 10⁹

  • -10⁹ ≤ target ≤ 10⁹

  • 只会存在一个有效答案

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


二、多解法实现(Java)

解法一:暴力枚举(双重循环)

思路解析

遍历数组中的每一个元素 nums[i],再遍历 i 之后的所有元素 nums[j],判断两者之和是否等于 target

核心特点:

  • 时间复杂度:O(n²),双重循环,最坏情况需遍历数组两次。

  • 空间复杂度:O(1),仅使用常数额外空间,无需额外数据结构。

Java 代码
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int n = nums.length;
        // 外层遍历每个元素
        for (int i = 0; i < n; i++) {
            // 内层遍历i之后的元素,避免重复使用同一元素
            for (int j = i + 1; j < n; j++) {
                if (nums[i] + nums[j] == target) {
                    return new int[]{i, j};
                }
            }
        }
        // 题目保证有解,此行仅为满足语法完整性
        return new int[0];
    }
}
    

解法二:哈希表(一次遍历,推荐)

思路解析

遍历数组时,用哈希表(Map)记录当前元素值与索引的映射关系。对每个元素 nums[i],计算补数 complement = target - nums[i]

  • 若补数已存在于哈希表中,说明之前遍历过的元素与当前元素之和为 target,直接返回两者索引。

  • 若补数不存在,将当前元素值和索引存入哈希表,继续遍历。

核心特点:

  • 时间复杂度:O(n),仅遍历数组一次,哈希表查询、插入操作均为 O(1)。

  • 空间复杂度:O(n),最坏情况需存储数组所有元素。

Java 代码
import java.util.HashMap;
import java.util.Map;

class Solution {
    public int[] twoSum(int[] nums, int target) {
        // 哈希表:key=元素值,value=元素索引
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int complement = target - nums[i];
            // 先查补数,再存当前元素,避免自身相加(如nums=[3,3], target=6)
            if (map.containsKey(complement)) {
                return new int[]{map.get(complement), i};
            }
            map.put(nums[i], i);
        }
        // 题目保证有解,此行仅为满足语法完整性
        return new int[0];
    }
}
    

解法三:哈希表(两次遍历)

思路解析

分两次遍历数组:

  1. 第一次遍历:将数组所有元素值与对应索引存入哈希表。

  2. 第二次遍历:对每个元素 nums[i],计算补数 complement = target - nums[i],判断补数是否存在于哈希表中,且索引不等于 i(避免使用自身元素)。

核心特点:

  • 时间复杂度:O(n),两次遍历数组,哈希表操作均为 O(1)。

  • 空间复杂度:O(n),哈希表需存储数组所有元素。

Java 代码
import java.util.HashMap;
import java.util.Map;

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        // 第一次遍历:存入所有元素值与索引
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i], i);
        }
        // 第二次遍历:查找补数,排除自身元素
        for (int i = 0; i < nums.length; i++) {
            int complement = target - nums[i];
            if (map.containsKey(complement) && map.get(complement) != i) {
                return new int[]{i, map.get(complement)};
            }
        }
        // 题目保证有解,此行仅为满足语法完整性
        return new int[0];
    }
}
    

三、三种解法对比

解法时间复杂度空间复杂度核心特点
暴力枚举O(n²)O(1)简单直观,易理解,适合入门;效率低,不适合大数据量
一次遍历哈希表O(n)O(n)最优解法,时间效率最高,面试首选;空间换时间,逻辑严谨
两次遍历哈希表O(n)O(n)逻辑清晰,易上手;需两次遍历,效率略低于一次遍历

四、复习要点

  1. 哈希表的核心作用:空间换时间,将原本 O(n) 的查找操作优化为 O(1),是提升算法效率的关键。

  2. 一次遍历哈希表的关键:先查后存,避免元素自身相加(如示例 3:nums = [3,3], target = 6,若先存后查会误判自身)。

  3. 暴力枚举的价值:虽效率低,但无需额外数据结构,可作为思路验证、边界测试的参考,面试中可补充说明,体现思维全面性。

  4. 边界场景注意:数组元素可能重复(如示例 3)、元素为负数(如 nums = [-1,-2,-3,-4,-5], target = -8),三种解法均能覆盖。