经典算法—两数之和!

坦诚相见吧,两数之和!

《两数之和》是算法学习过程中最最经典也是最最基础的一个问题。

力扣、牛客等刷题网站排行最高的就是两数之和了,经典就有其经典的道理,《两数之和》因为本身并没有太高的难度。

而且也能体现出一些算法的思想,所以作为入门必刷题来说,再合适不过了。

那么咱们先来看题目吧!

● 来详细分析一下题目

● 首先有一个给定的数组, 数组内有若干数字

var nums = [ 11, 15, 3, 8, 2, 6 ]

● 确定一个目标值

var target = 9

● 接下来就是需求分析

○ 从给出的 nums 数组中找到两个数字, 两个数字的和是 target

○ 有且只有一个唯一解

○ 找到两个数字以后, 返回两个数字的下标

● 比如

○ 这里的答案就是 2 和 5

○ 因为 nums[2] + nums[5] = 9 符合要求

开始搞起来

暴力破解

作为一个入门的程序员, 一个小趴菜, 我都觉得这个玩意对于我来说实在是太简单了

明白了!挨个对比挨个找一遍不就得了,小小问题,难不倒真正的勇士,看我破他护体真气,双重循环暴力解法奉上!

var twoSum = function(nums, target) {
 for (var i = 0; i < nums.length; i++) {
 for (var j = i + 1; j < nums.length; j++) {
 if (nums[i] + nums[j] === target) {
 return [ i, j ]
 }
 }
 }
}

完全没有问题, 搞定, 我真是太棒了

给我的小伙伴们看完这个答案以后, 我的嘴角微微上扬, 已经准备好接受大家的表扬了。

你们这是什么眼神, 我怎么了, 难道不对吗??

但是提交上去之后,分数并不高,说这种方法性能不好,暴力解法采用双重循环嵌套的话,虽然解决了问题,但是执行判断的次数大约是:(n-1) + (n-2) + (n-3) + ... + 1次

从之前学过的时间复杂度来分析的话,暴力解法的时间复杂度大约是O(n(n-1))即O(n²-n),虽然时间复杂度小于O(n²)。

但是实际也没好到哪儿去,当然分数不高咯。

好吧,好吧,真是拿你没有办法(扶眼镜)~接下来,我们来转换思路,另辟蹊径!

秘法 · 空间换时间

所谓的空间换时间,其实指的就是,针对这样两层遍历的情况,我们可以在遍历的过程中,一边去判断,一边做存储。

判断找到了就返回,没找到,那就存起来等到下一次判断的时候看看是否能找的到,这样一边判断、一边存储的方式当然快咯。

因为毕竟只需要遍历一次嘛,呐,举个栗子:

有一队小朋友,要找到他们做任务的搭档,我们就可以先挨个把小朋友叫过来(开始遍历),让他从一个本子上去找,看本子上的照片有没有自己的搭档(做判断)。

如果找到了,那小朋友就可以大声报告出来(返回结果),如果没找到呢,就把这个小朋友的照片贴在本子上,然后叫下一个小朋友进来找(存储后继续遍历)。

这样是不是性能和效率就高很多了,非常Nice,换个思路,果然有另外收获!

好了,开打,开打!代码奉上!

// 空间换时间解法
const twoSum = (nums, target) => {
// 创建⼀个Map对象的数据,键值对中键为数组中的元素与⽬标的差值,值为这个元素的索引
const map = new Map(); // 存储⽅式 {key使⽤⽬标差值=>值使⽤索引存储}
// 开始遍历数组
for (let i = 0; i < nums.length; i++) {
// 先算出当前这个元素匹配的元素应该是⼏
let diff = target - nums[i]
// ⼀边顺⼿做判断,找到啦!就返回
// 判断map中是否有符合⽬标差值的键名,有则返回对应的索引(map中对应的值)及当前遍历数组的索引
if (map.has(diff)) {
return [map.get(diff), i];
 }
// ⼀边做存储,没找到,就存起来!
// 如果map中没找到符合⽬标差值的键名,则将本次循环数组获取的数组元素作为键名,及索引作为键值写⼊到map中记录
map.set(nums[i], i);
 }
};

这次的方法,我们只用了一次循环,就解决了问题,时间复杂度当然就是O(n)咯,只是在函数运行的过程中,创造了一个 map对象在占用内存空间,虽然函数之后map对象被回收了,但是总的来说是消耗了一些内存的。

但是虽然计算的时候占用了内存,但是非常明显的提高了效率和性能,ok,ok,得偿所愿!

最后划一个道道

所以说,所谓的空间换时间,真的非常适合用在一些查找类的算法需求中,以后再碰到这样的需求,我们不要再研究双重循

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值