1. 概述
本教程将展示如何在Java中实现一个算法:找出数组中所有和等于给定数字的数字对。我们将重点介绍两种不同的解题思路。
第一种方法会找出所有可能的组合(允许重复),第二种方法则只返回唯一的数字组合,剔除冗余对。
针对每种思路,我们都会提供两种实现方式:
- 传统的
for
循环实现 - Java 8 Stream API 实现
2. 返回所有匹配对(含重复)
2.1 暴力解法
我们将使用暴力嵌套循环遍历整数数组,找出所有满足 i + j = sum
的数字对。**这种方法的时间复杂度为 O(n²)**。
以目标和 6
为例,使用以下输入数组:
int[] input = {2, 4, 3, 3, 5, 7, 1};
算法应返回所有可能的组合(含重复):
{2,4}, {4,2}, {3,3}, {3,3}
当找到满足条件的数字对时,通过工具方法 addPairs(i, j)
收集结果。
传统 for 循环实现
for (int i = 0; i < input.length; i++) {
for (int j = 0; j < input.length; j++) {
if (i != j && input[i] + input[j] == sum) {
addPairs(input[i], input[j]);
}
}
}
Java 8 Stream API 实现
IntStream.range(0, input.length)
.forEach(i -> IntStream.range(0, input.length)
.filter(j -> i != j && input[i] + input[j] == sum)
.forEach(j -> addPairs(input[i], input[j])));
⚠️ 踩坑提醒:这种方法会包含重复对(如 {2,4}
和 {4,2}
),且时间复杂度较高,仅适用于小规模数据。
3. 返回唯一匹配对(去重)
3.1 优化解法
本方法需要更高效的算法,仅返回唯一数字组合。核心思路:
- 使用 HashMap 存储已处理的数字
- 检查
sum - currentNum
是否已存在 - 避免重复记录(如
{2,4}
和{4,2}
视为同一组合)
使用相同的输入数组和目标和 6
,预期输出:
{2,4}, {3,3}
传统 for 循环实现
Map<Integer, Integer> seen = new HashMap<>();
for (int num : input) {
int complement = sum - num;
if (seen.containsKey(complement)) {
addPairs(complement, num);
seen.remove(complement); // 避免重复使用
} else {
seen.put(num, complement);
}
}
✅ 优化点:时间复杂度降至 **O(n)**,仅用单层循环。
Java 8 Stream API 实现
Map<Integer, Integer> pairs = new HashMap<>();
IntStream.range(0, input.length).forEach(i -> {
int current = input[i];
int complement = sum - current;
if (pairs.containsKey(current)) {
if (pairs.get(current) != null) {
addPairs(current, complement);
}
pairs.put(current, null); // 标记已使用
} else if (!pairs.containsValue(complement)) {
pairs.put(complement, current);
}
});
⚠️ 关键逻辑:
- 通过
containsValue
检查避免反向重复 - 用
null
标记已匹配的数字,防止二次利用
4. 总结
本文对比了在Java中解决两数之和问题的两种核心策略:
- 暴力解法:简单直接但效率低(O(n²)),适合快速验证
- 优化解法:利用HashMap去重且高效(O(n)),适合生产环境
每种策略都提供了传统循环和Stream API两种实现。完整代码示例可在GitHub仓库获取(Maven工程,可直接编译运行)。
💡 开发建议:实际项目中优先选择优化解法,但需注意HashMap的内存开销。对于超大规模数据,可考虑排序后使用双指针法进一步优化。