题目描述:
给定一个整数数组 nums
和一个目标值 target
,请你在数组中找出 两个数,使它们的和等于 target
,并返回它们的数组下标。
假设每种输入只有唯一解,且同一个元素不能重复使用。
示例:
输入:nums = [2, 7, 11, 15], target = 9
输出:[0, 1] # 因为 nums[0] + nums[1] = 2 + 7 = 9
哈希表解法详解:
为什么用哈希表?
-
暴力解法需要两层循环(O(n²) 时间复杂度),而哈希表可以 用空间换时间,将查找时间降到 O(1),整体复杂度优化到 O(n)。
核心思路:
-
遍历数组,每次检查当前数字的 互补数complement(即
target - nums[i]
)是否在哈希表中。 -
如果存在,直接返回当前下标和互补数的下标。
-
如果不存在,将当前数字及其下标存入哈希表,供后续查找。
Python代码实现:
def twoSum(nums, target):
hash_map = {} # 哈希表,存储 {数值: 下标}
for i, num in enumerate(nums):
complement = target - num
if complement in hash_map: # O(1) 查找
return [hash_map[complement], i]
hash_map[num] = i # 存入当前数字
return []
# 测试
print(twoSum([2, 7, 11, 15], 9)) # 输出 [0, 1]
Java 代码实现:
import java.util.HashMap;
public class TwoSum {
public static int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hashMap = new HashMap<>(); // 哈希表:key=数值,value=下标
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (hashMap.containsKey(complement)) { // O(1) 查找互补数
return new int[]{hashMap.get(complement), i}; // 找到解,返回两个数的下标
}
hashMap.put(nums[i], i); // 存入当前数和下标
}
return new int[]{}; // 无解(题目保证有解,可不写)
}
public static void main(String[] args) {
int[] nums = {2, 7, 11, 15};
int target = 9;
int[] result = twoSum(nums, target);
System.out.println("[" + result[0] + ", " + result[1] + "]"); // 输出 [0, 1]
}
}
-
哈希表的选择
-
使用
HashMap<Integer, Integer>
,因为需要存储 数值(Key) 和 下标(Value)。
-
-
时间复杂度
-
O(n):只需遍历一次数组,每次哈希表操作为 O(1)。
-
-
空间复杂度
-
O(n):最坏情况下需要存储所有元素。
-
代码解析:
(1)HashMap<Integer, Integer> hashMap = new HashMap<>();
为什么都用 Integer
?
-
数值(Key)
-
题目中的数组元素是整数(如
nums = [2, 7, 11, 15]
),所以用Integer
存储。 -
Java 的泛型不支持基本类型(如
int
),必须用包装类Integer
。但实际使用时,Java 会自动装箱(int
→Integer
)和拆箱(Integer
→int
)
-
-
下标(Value)
-
数组下标是整数(如
0, 1, 2,...
),所以也用Integer
。 -
虽然下标不会为负数,但
Integer
可以兼容所有int
范围的值。
-
若题目改成字符串数组(如 ["a", "b"]
),则哈希表声明为:
HashMap<String, Integer> hashMap = new HashMap<>(); // Key=String, Value=下标
(2)hashMap.containsKey(complement)
-
作用:检查哈希表中是否存在键为
complement
的条目
(3)hashMap.get(complement)
-
作用:从哈希表中获取
complement
对应的 下标值(即之前存储的value
) -
示例:若
hashMap = {2:0, 7:1}
,且complement = 2
,则hashMap.get(2)
返回0
(4)return new int[]{hashMap.get(complement), i}
-
作用:返回一个包含两个下标的整数数组,表示找到的两个数的位置。最终返回的数组格式:
[互补数的下标, 当前数的下标]
为什么用 int[]
?
-
返回值类型:题目要求返回两个下标(例如
[0, 1]
),而数组是存储多个整数的最简单结构。 -
int[]
表示一个 整数数组,比如[1, 2]
或[0, 3]
。
new int[]{...}
的含义?
-
这是 Java 中 动态初始化数组 的语法:
-
new int[]
:创建一个新的整数数组。 -
{value1, value2}
:初始化数组元素,直接填充值
对比其他初始化方式
写法 | 说明 |
---|---|
new int[]{a, b} | 动态初始化:直接指定元素,数组长度由元素个数决定(这里是 2)。 |
new int[2]; arr[0]=a; arr[1]=b | 先声明长度,再单独赋值(更冗长,不推荐在这里使用)。 |
int[] arr = {a, b}; return arr; | 先定义数组变量再返回(多一行代码,没必要)。 |
(5)hashMap.put(nums[i], i);
-
作用:存入当前数和下标
-
此时哈希表状态:
{2: 0}