题目内容
写一个叫twoSum的方法,传入一个整数数组nums和一个整数target,要求返回两个数字的下标,使这两个下标所对应的数相加为target。
注意
1.不会出现某个输入无解的情况(边际情况忽略)
2.元素不能重复使用
3.答案返回顺序随意
测试程序样例
class Solution {
public int[] twoSum(int[] nums, int target) {
//在这里完成我们的代码
}
}
示例
输入:nums = [2, 7, 11, 15], target = 9
输出:[0, 1]
解释:nums[0] + nums[1] = 2 + 7 = 9,所以返回 [0, 1]。
解题思路
在面对这个问题时,我首先考虑了一种简单的解决方法,即使用两层循环来遍历数组,寻找满足条件的数对,在满足条件时立即返回结果,不满足则继续遍历。以下是我的初始解答:
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = new int[2]; // 声明并初始化结果数组
for (int i = 0; i < nums.length; ++i) {
for (int j = i + 1; j < nums.length; ++j) { // 注意这里从 i+1 开始,避免重复计算
if (target == nums[i] + nums[j]) {
result[0] = i;
result[1] = j;
return result; // 找到目标,返回结果
}
}
}
return result; // 如果没有找到目标,返回初始值[0, 0]
}
}
这种时间复杂度为O(n^2)的简单粗暴的算法顺利帮我通过了测试,测试结果如下
耗时:45毫秒 击败45.5%的Java用户
占用空间:43.7MB 击败70.19%的Java用户
虽然在空间占用上表现不错,但是这个时间让我这个学习时长两年半的大学牲感到差强人意,我对这道题进行了进一步的思考:
- 这个解法的时间复杂度很高,尤其是对于大规模数据。我是否可以通过更有效的方法来解决这个问题?
- 我的解答没有考虑空间复杂度,它创建了一个新的数组来存储结果。是否有更节省内存的方式?
同时,LeetCode上还有一个追问在若有若无的提醒我:能否在不使用双重循环的情况下解出这道题?
我们顺着这个问题继续思考,如果不使用双重循环,那就要在使用一个循环的情况下完成数组之间的匹配,考虑到Java语言的特性,我选择了Hash Table来提高效率,利用哈希表存储数组元素和它们的索引的映射关系,种方法具有更低的时间复杂度(O(n)),因为哈希表的查找操作通常是O(1)。同时,它减少了额外的内存消耗。
方法优化
import java.util.HashMap;
import java.util.Map;
class Solution {
public int[] twoSum(int[] nums, int target) {
// 使用 HashMap 存储已经遍历过的数字及其索引
Map<Integer, Integer> selections = new HashMap<>();
for (int i = 0; i < nums.length; ++i) {
int complement = target - nums[i];
// 检查是否已经存在与当前数字相加等于目标值的数字
if (selections.containsKey(complement)) {
// 如果找到满足条件的数字,返回它们的索引
return new int[]{i, selections.get(complement)};
}
// 将当前数字及其索引添加到 HashMap 中
selections.put(nums[i], i);
}
// 如果没有找到满足条件的数字对,抛出异常
throw new IllegalArgumentException("No valid solution found!");
}
}
附上运行结果:
耗时:2毫秒 击败81.32%的Java用户
占用空间:43.9MB 击败37.52%的Java用户
抛开占用空间变高不谈,单看2毫秒的耗时还是可以说进步明显的
最后希望这篇文章可以帮到大家!