【LeetCode热题100】No.1——两数之和(Java)

大家好!今天开始我们正式开启 LeetCode 热题 100 系列的讲解,第一题就是经典的 "两数之和"。这道题不仅是 LeetCode 的入门必刷题,更是面试中高频出现的基础题,掌握它的解题思路,能帮我们建立对数组类问题的基本认知。接下来,我们就从题目分析、解法推导到代码实现,一步步把这道题吃透。

一、题目描述

首先,我们先明确题目要求(基于 LeetCode 官方原题):

  • 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
  • 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
  • 你可以按任意顺序返回答案。

示例

比如输入:nums = [2,7,11,15],target = 9

因为 2 + 7 = 9,所以返回 [0,1](数组下标从 0 开始)。

提示

  • 2 <= nums.length <= 10⁴(数组长度至少为 2,保证有解)
  • -10⁹ <= nums[i] <= 10⁹
  • -10⁹ <= target <= 10⁹
  • 只会存在一个有效答案

二、解题思路分析

解决这道题,我们可以从 "暴力解法" 入手,再逐步优化,理解不同解法的时间复杂度差异,这也是面试中面试官希望看到的思考过程。

1. 暴力解法:双重循环(入门思路)

思路逻辑

最直观的想法是:遍历数组中的每一个元素,对于当前元素 nums[i],再遍历它后面的所有元素 nums[j](j > i),判断 nums[i] + nums[j] 是否等于 target。如果等于,直接返回 [i, j]即可。

代码实现
java 复制代码
public class No1 {
    public static void main(String[] args) {
        int[] nums = {2,7,11,15};
        int target = 13;
        int[] result = Solution.twoSum(nums, target);
        System.out.println(Arrays.toString(result));
    }

    public static class Solution {
        public static int[] twoSum(int[] nums, int target) {
            for (int i = 0; i < nums.length; i++) {
                for (int j = 0; j < nums.length; j++) {
                    if(target == nums[i]+nums[j]){
                        return new int[]{i,j};
                    }
                }
            }
            return null;
        }
    }
}
复杂度分析
  • 时间复杂度:O (n²)。外层循环执行 n 次,内层循环平均执行 n/2 次,整体是二次方级别的操作,当数组长度很大(比如接近 10⁴)时,效率会很低。
  • 空间复杂度:O (1)。没有额外使用与数组长度相关的存储空间,只用到了几个变量。
缺点

暴力解法虽然思路简单,但时间复杂度太高,在面试中通常不会被接受,我们需要更高效的方法。

2. 优化解法:哈希表(推荐思路)

核心思路:用空间换时间

暴力解法的问题在于 "查找互补元素" 的过程太慢(每次都要遍历后面的元素)。如果我们能把 "查找互补元素" 的时间从 O (n) 降到 O (1),整体时间复杂度就能降到 O (n)。

这里的 "互补元素" 指的是:对于当前元素 nums[i],能和它组成 target 的元素是 complement = target - nums[i]。我们需要快速判断 complement 是否在数组中,并且获取它的下标。

哈希表(HashMap) 正好可以实现 "键值对" 的快速查找:

  • 把数组中的元素作为 "键(key)",元素的下标作为 "值(value)" 存入哈希表。
  • 遍历数组时,对于当前元素 nums[i],计算 complement = target - nums[i]。
  • 检查哈希表中是否存在 complement 这个键:
  • 如果存在,说明之前已经遍历过这个互补元素,直接返回 [哈希表中complement对应的值, i]。
  • 如果不存在,就把当前元素 nums[i] 和它的下标 i 存入哈希表,继续遍历下一个元素。
为什么能保证不重复?

因为我们是 "边遍历边存表",每次查找的都是已经遍历过的元素(即下标小于当前 i 的元素),所以不会出现同一个元素被重复使用的情况。

代码实现(Java 版)
java 复制代码
public class No1point1 {
    public static void main(String[] args) {
        int[] nums = {2, 7, 9, 11};
        int target = 11;
        int[] result = No1.Solution.twoSum(nums, target);
        System.out.println(Arrays.toString(result));
    }
    
    public int[] twoSum(int[] nums, int target) {
        // 初始化哈希表,key存数组元素,value存元素下标
        Map<Integer, Integer> map = new HashMap<>();
        int n = nums.length;
        // 遍历数组
        for (int i = 0; i < n; i++) {
            // 计算互补元素
            int complement = target - nums[i];
            // 检查互补元素是否在哈希表中
            if (map.containsKey(complement)) {
                // 存在则返回结果(互补元素的下标在前,当前下标在后)
                return new int[]{map.get(complement), i};
            }
            // 不存在则将当前元素和下标存入哈希表
            map.put(nums[i], i);
        }
        return null;
    }
}
复杂度分析
  • 时间复杂度:O (n)。只遍历了一次数组,每次哈希表的查找和插入操作都是 O (1),整体是线性时间。
  • 空间复杂度:O (n)。最坏情况下,需要把数组中所有元素都存入哈希表,存储空间与数组长度成正比。
优点

用少量的空间代价,换来了时间复杂度的大幅降低,是面试中的最优解,也是实际工程中推荐使用的方法。

三、测试案例验证

为了确保代码的正确性,我们可以用题目中的示例和一些边缘案例进行测试。

测试案例 1:基础案例

输入:nums = [2,7,11,15],target = 9

输出:[0,1]

测试案例 2:元素为负数

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

输出:[1,2]

测试案例 3:元素顺序不同

输入:nums = [3,3],target = 6

输出:[0,1]

四、总结

"两数之和" 虽然是一道简单题,但它涵盖了两个重要的解题思路:

  1. 暴力解法:适合入门理解问题,但效率低,不推荐实际使用。
  1. 哈希表解法:用空间换时间,是最优解,需要掌握哈希表的 "快速查找" 特性。

这道题的核心启示是:当遇到 "需要快速查找某个元素是否存在" 的场景时,优先考虑哈希表这种数据结构,它能极大提升查找效率。

下一篇我们会讲解 LeetCode 热题 100 的第二题,感兴趣的同学可以持续关注~如果有疑问,欢迎在评论区留言讨论!

相关推荐
断春风8 小时前
SpringBoot 集成 XXL-JOB
java·spring boot·后端
橘子海全栈攻城狮8 小时前
【最新源码】基于springboot的会议室预订系统设计与实现 014
java·开发语言·前端·spring boot·后端·spring·自动化
另寻沧海8 小时前
C++ Lambda表达式的隐式转换陷阱
java·c++·算法
菜鸟233号8 小时前
力扣654 最大二叉树 java实现
java·算法·leetcode
小张程序人生8 小时前
《系统掌握 ShardingSphere-JDBC:分库分表、读写分离、分布式事务一网打尽》
java·mysql
TL滕8 小时前
从0开始学算法——第十四天(数组与搜索)
数据结构·笔记·学习·算法
SMF19198 小时前
解决在 Linux 系统中,当你尝试以 root 用户登录时遇到 “Access denied“ 的错误
java·linux·服务器
ByNotD0g8 小时前
Golang Green Tea GC 原理初探
java·开发语言·golang
mit6.8249 小时前
tree
算法
9号达人9 小时前
Jackson序列化让验签失败?破解JSON转义陷阱
java·后端·面试