本题连接 leetcode-cn.com/problems/tw…算法
看到这道题的第一反应就是,挺简单的,遍历两遍数组就能解决,咱们尝试一下。数组
let twoSum1 = function (nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) {
return [i,j]
}
}
}
}
复制代码
的确解决了,但时间复杂度为o(n^2),最终经过时间为204ms,很不推荐,咱们能不能缩短期呢?bash
咱们假设最终找到的两个值一个是x,一个是y,x + y = target,也就等价于 y = target - x。咱们只须要操做x就能解决这道题。思路是,判断target - x 这个值是否存在于这个数组中并与x的数组下标不相等。ui
let twoSum2 = function (nums, target) {
for (let i = 0; i < nums.length; i++) {
if (nums.indexOf(target - nums[i]) > -1 && nums.indexOf(target - nums[i]) !== i) { // 排除两个值相等的状况
return [i, nums.indexOf(target - nums[i])];
break; // 防止最终结果的下标出现两次
}
}
}
复制代码
最终顺利经过,但最后的时间为208ms,为何一层循环和两层循环的经过时间这么接近呢?由于twoSum2虽然只用了一层循环,但用到了js内置的方法indexOf(),这里面也有一层循环,其实最终仍是两层循环,这个方法也不推荐。spa
咱们用一个对象把数组里的下标和值都存起来,对象里的键表明数组的值,对象里的值表明数组下标,再用twoSum2里的思路去解题,这样只须要循环一次。code
let twoSum3 = function(nums,target){
let obj = {};
for(let i=0; i<nums.length; i++){
obj[nums[i]] = i
}
for(let i=0; i<nums.length; i++){
if(obj[target-nums[i]] && obj[target-nums[i]] !== i){
return [i,obj[target-nums[i]]]
}
}
}
复制代码
这个方法时间复杂度为o(n),最终经过的时间是80ms,比以前快了两倍多,除了空间换时间,解题思路和twoSum2彻底同样。对象
逛了下社区的解题,有不少同窗都用了哈希表来存值,最终实现空间换时间,下降时间复杂度。其实跟twoSum3的思路是同样的,咱们也试着用哈希表写一个。leetcode
let twoSum4 = function(nums, target) {
const map = new Map()
for(let i = 0; i < nums.length; i++){
if (map.has(target - nums[i])){
return [ map.get(target - nums[i]), i ]
}
map.set(nums[i], i)
}
};
复制代码
最终经过时间84ms,跟twoSum3差很少。get
本题最主要的思路就是用空间换时间,我的认为若是能很明显地减小时间复杂度,用空间换时间是值得的。反正无论怎样,写出来的算法时间复杂度是o(n^2)是很糟糕的,咱们必定要想尽办法,减小时间复杂度。io