这段代码是解决「LeetCode 1. 两数之和」问题的经典哈希表解法,核心思路是通过哈希表记录已遍历元素的索引,实现快速查找 "互补元素",从而将时间复杂度优化到线性级别。下面从「问题理解→核心思路→代码逐行解析→实例演示」四个维度详细讲解:
一、问题理解
「两数之和」问题要求:给定一个整数数组 nums 和一个目标值 target,在数组中找到两个不同的元素 ,使它们的和等于 target,返回这两个元素的索引 (注意:索引从 0 开始,且第一个索引必须小于第二个索引)。题目保证:数组中一定存在唯一解(无需考虑无解情况)。
二、核心思路
暴力解法(两层循环遍历所有可能的两数组合)的时间复杂度是 O(n²),效率较低。而哈希表解法的核心优化是:用哈希表记录「已遍历元素的值→索引」 ,对于当前遍历的元素 x,只需检查哈希表中是否存在 target - x(即 "互补元素"):
- 若存在:说明这两个元素的和为
target,直接返回它们的索引(哈希表中记录的索引是之前的,当前索引是后遍历的,满足 "前小后大")。 - 若不存在:将当前元素
x和其索引存入哈希表,继续遍历。
三、代码逐行解析
java
运行
class Solution {
public int[] twoSum(int[] nums, int target) {
// 1. 创建哈希表:key是数组元素的值,value是该元素的索引
Map<Integer, Integer> idx = new HashMap<>();
// 2. 遍历数组(j是当前元素的索引)
// 循环没有终止条件:因为题目保证有唯一解,一定会在找到时返回
for (int j = 0;; j++) {
// 2.1 取当前元素的值x
int x = nums[j];
// 2.2 检查哈希表中是否存在"互补元素"(target - x)
if (idx.containsKey(target - x)) {
// 若存在:返回互补元素的索引(哈希表中存储的)和当前索引j
return new int[]{idx.get(target - x), j};
}
// 2.3 若不存在:将当前元素x和其索引j存入哈希表,继续遍历
idx.put(x, j);
}
}
}
关键细节拆解:
-
哈希表的作用
Map<Integer, Integer> idx = new HashMap<>():哈希表的键(key)是数组中已经遍历过的元素值,值(value)是该元素对应的索引。这样可以通过containsKey方法O (1) 时间 判断 "互补元素" 是否存在,通过get方法O (1) 时间获取其索引。 -
循环设计
for (int j = 0;; j++):- 循环变量
j是当前遍历元素的索引,从 0 开始递增。 - 没有终止条件(
;;):因为题目明确 "一定有解",所以循环会在找到符合条件的两个元素时通过return终止,不会无限循环。
- 循环变量
-
核心逻辑:查找互补元素
int x = nums[j]:当前遍历的元素值为x。target - x:需要寻找的 "互补元素"(两者之和为target)。idx.containsKey(target - x):检查哈希表中是否存在之前遍历过的 "互补元素"。- 若存在:
idx.get(target - x)得到互补元素的索引(必然小于j,因为它是之前遍历的),直接返回这两个索引。 - 若不存在:
idx.put(x, j)将当前元素和索引存入哈希表,继续遍历下一个元素。
- 若存在:
四、实例演示
以经典测试用例 nums = [2, 7, 11, 15],target = 9 为例,演示执行过程:
- 初始状态 :哈希表
idx为空,j = 0。 - j=0 :
x = nums[0] = 2。- 检查是否有
target - x = 9 - 2 = 7?哈希表为空,无。 - 存入
idx.put(2, 0)→ 哈希表:{2:0}。
- j=1 :
x = nums[1] = 7。- 检查是否有
target - x = 9 - 7 = 2?哈希表中存在2,对应索引0。 - 满足条件,返回
new int[]{0, 1}→ 结果正确。
五、复杂度分析
- 时间复杂度 :
O(n)只需遍历一次数组(n是数组长度),哈希表的containsKey和put操作均为O(1)平均时间复杂度。 - 空间复杂度 :
O(n)最坏情况下,需要在哈希表中存储n-1个元素(找到解时的前一个元素)。
总结
该解法的核心是利用哈希表的快速查找特性,将 "查找互补元素" 的时间从暴力解法的 O(n) 优化到 O(1),整体效率大幅提升。这种 "以空间换时间" 的思路是哈希表的典型应用,也是大厂面试中高频考察的基础算法思想。