算法学习-代码效率优化方法论-七日打卡

556 阅读4分钟

如何衡量一段代码的优劣呢?

一般我们会从两个维度去考虑一段代码的质量:

  1. 时间复杂度
  2. 空间复杂度

顾名思义,其实时间复杂度就是说这段代码的计算量所能消耗的时间,而空间复杂度就是这段代码所占据的内存空间。

那么我们应该怎么来定义复杂度呢? image.png

复杂度的定义与特点

定义

复杂度是一个关于输入量n的函数。 eg:假设你的代码复杂度是f(n),那么用大写字母O将其括起来就可以表示复杂度了 --- O(f(n))

特点

  • 与常系数无关

例如O(n) + O(n) = O(2n), 其实O(n)复杂度和O(2n)复杂度是一样的,我们通常会忽略常系数对复杂度的影响

  • 多项式级相加的复杂度,会取结果最大的那一个作为最后的结果

O(n^2) + O(n),明显n^2在输入量n逐渐变大的情况下,变化会更大,所以我们就说复杂度是O(n^2)即可

  • O(1)是一个特殊的复杂度:输入量n与消耗的资源无关

O(1)表示的是当前复杂度和输入n无关。例如你的代码处理100条数据是消耗3个时间单元和1个空间单元,处理500条数据依然还是消耗3个时间单元和1个空间单元,那么就是输入量与消耗资源无关。

提高代码效率的方法

我们从上面已经知道了衡量代码效率的方法,那么我们应该怎么着手去优化提高我们代码的效率呢?

总的策略就是降低代码的时间复杂度和空间复杂度。

但是对于一段代码来说往往时间和空间两个是互斥的,如果我们想要降低时间复杂度,那么无疑就会增加空间复杂度。 举一个生活中的🌰,就像我们平时生活中开车过红绿灯,如果只有这一条路(空间)那么我们就只能在这等着红灯,当车越来越多的时候,就会消耗大家很多时间,但是当我们修建了立交桥之后,就会有更多的选择空间,就会大大减少等待红灯的时间。

而对我们来说,时间永远都要比空间更加重要,因为时间拿钱买不来,而空间我们起码可以拿钱来进行扩容。 空间是廉价的,时间是昂贵的 image.png

  1. 暴力解法:在没有任何时间和空间的限制下,将目标达成
  2. 剔除无效操作:将代码中没有必要的计算、无效的存储删除来优化时间和空间复杂度
  3. 时空转换:设计合理的数据结构,将时间向空间转换

增删查:数据的基本操作

一般一段算法的实现最常设计的三个操作就是:增、删、查。 而我们对一个算法的优化和实现只要围绕这三个为重心去思考展开即可:

  1. 分析这段代码对数据进行了那些操作
  2. 这些操作中有哪些操作是最消耗性能的,对时间复杂度的损耗是最高的?
  3. 考虑有哪种数据结构可以帮助提高数据操作的使用效率。

以上三点就是构成我们实现代码效率优化的方法论。

  1. 按照元素索引查找
    • 对于数组这些天生拥有索引的数据结构来说十分简单
    • 对于链表这种,通过指针进行连接的就需要知道前面一个元素
  2. 按照元素特征值查找
    • 对于字典类型的数据来说,key就相当是特征,value就是值,查找起来非常方便
    • 对于数组和链表来说就需要循环对比每个元素来进行比较值的特征是否符合

  1. 在复杂数据结构的末尾添加数据
    • 不会影响数据的原始位置
  2. 在复杂数据结构的中间添加数据
    • 会影响到数据原始的位置

  1. 在复杂数据结构的末尾删除
    • 不会影响到原先数据的位置
  2. 在复杂数据结构的中间位置进行删除
    • 会影响到之前数据的原始位置