这道题很明显,像我们这种算法也不会的人,第一反应便是暴力for循环,当然暴力for循环是能够通过这题的
var twoSum = function(nums, target) {
let length = nums.length;
for (let start = 0; start < length - 1; start++) {
for (let end = start + 1; end < length; end++) {
if (nums[start] + nums[end] === target) {
return [start, end]; // 返回找到的两个数的索引组成的数组
}
}
}
return []; // 如果没有找到符合条件的组合,返回空数组
};
或者用js自带的hasmap
var twoSum = function(nums, target) {
const hashMap = new Map(); // 使用Map对象来模拟哈希表,存储元素值和其对应的索引
for (let i = 0; i < nums.length; i++) {
const currentNum = nums[i];
const targetNum = target - currentNum;
// 在哈希表中查找是否存在目标元素对应的索引
if (hashMap.has(targetNum)) {
return [hashMap.get(targetNum), i];
}
// 将当前元素及其索引存入哈希表
hashMap.set(currentNum, i);
}
return [];
};
很显然,这种解法的时间复杂度是O(n2),那有没有更高效的解法呢?那便是哈希表了
什么是哈希表
这里我们只简单说明一下。 哈希表(Hash Table):也叫做散列表。是根据关键码值(Key Value)直接进行访问的数据结构。
哈希表通过「键 key 」和「映射函数 Hash(key) 」计算出对应的「值 value」,把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做「哈希函数(散列函数)」,存放记录的数
对于我们这种小白而言,只需要知道
- 哈希表可以通过索引访问它对应的数据就行
- 哈希表查找的时间复杂度是O(1)的 我们经常用的数据就是一张哈希表,哈希表中的关键字就是数据的索引下标,通过下标可以直接访问数组中的元素。
那我们如何使用哈希表写这道题呢?
- 这道题本身如果通过暴力遍历的话也是很容易解决的,时间复杂度在 O(n2)
- 由于哈希查找的时间复杂度为 O(1),所以可以利用哈希容器 map 降低时间复杂度
- 遍历数组 nums,i 为当前下标,每个值都判断hasMap中是否存在 target-nums[i] 的 key 值
- 如果存在则找到了两个值,如果不存在则将当前的 (nums[i],i) 存入 map 中,继续遍历直到找到为止 如果最终都没有结果返回异常即可。
这里我们就可以写出答案出来了
用哈希表
var twoSum = function(nums, target) {
let hashMap = {};
for (let i = 0; i < nums.length; i++) {
let preNum = nums[i];
let targetNum = target - preNum;
let targetIndex = hashMap[targetNum];
if (targetIndex!== undefined) {
return [targetIndex, i];
} else {
hashMap[preNum] = i;
}
}
};
这里建议大家自己画图模拟一下,感受更加深刻
如果你自己模拟了还是无法理解,可以看这些图,
我们用输入nums 为 [2,7,11,15],target为13为例
当i = 0的时候,preNum = 2,targetNum = 11,这时候hasMap为空,所以targetIndex为undefined,所以我们将key=preNum,value = i,即将[2,0]存入hasMap中
再次循环,i=1,preNum = 7,targetNum = 6,这时候hashMap[targetNum],即hashMap[6]为undefined,所以我们将key=preNum,value = i,即将[7,1]存入hasMap中
再次循环,i=2,preNum =11,targetNum = 2,诶👍,这时候hashMap[targetNum],即hashMap[2]有值,为0,所以我们就找到了,返回答案即可
总结
如果在面试做题目的时候遇到需要判断一个元素是否存在集合中出现过的场景,则应该第一个想到哈希表