📢 声明:博主gitee----附博主学习笔记
文章前题:
❓ 思考:当我们设计出一个算法后如何去评价其好与坏呢(好与坏即算法的效率高低)?
👀 答案:两个方面(时间复杂度 + 空间复杂度),下面正式引入主题
文章目录
一、时间复杂度
💨 时间复杂度即算法的运行速度,如今,空间的代价相对较小,所以可以牺牲空间来换取时间(提升算法的效率)
那么问题来了,如何衡量一个算法的时间复杂度?
首先先要明确一个点:时间复杂度是一个大概,不是精确的算法运行时间
我们选择算法中基本操作(基本是循环中的一个语句)执行的次数被称为时间复杂度
👿 表示法:O的渐近表示法
👇 我们看这样一个例子:我们看 count++ 这条代码执行多少次
☝️ 很明显上述基本操作的代码(count++)执行次数为 :
N * N + 2 * N + 10
😞 但是由于我们在计算时间复杂度的时候,是计算一个大概的执行次数,这里使用大 O 渐进表示法化简基本操作的执行次数
大O渐进表示法规则:😲
- 用常数 1 替换掉运行时间中的所有加法常数
- 只保留最高阶项
- 如果最高阶存在且不是常数 1 则去掉最高项前面的系数
- 如果得到的是一个仅有常数的执行次数,一律使用O(1)表示
- 不一定 N 是变量,只是用 N 来表示问题的规模
以上代码的时间复杂度使用大O表示法化简后:O(N^2)常数和小阶数的项都被省略掉
时间复杂度有以下三种种类:
- 最坏时间复杂度:运行的最大次数(上界)🔼
- 平均时间复杂度:根据代码不同情况而定
- 最好时间复杂度:运行的最少次数(下界)🔽
注意:平时讨论的时间复杂度,都是在最坏情况下的时间复杂度,即第一种时间复杂度
二、空间复杂度
空间复杂度是一个算法在运行过程中,临时占用存储空间的量度,同样用大 O 表示法
方法:
去看算法中有没有随着问题的规模增大变量规模增大的情况
没有上述情况:
O(1)
有这样的情况:
依不同算法而定
三、练习题
练习一、
步骤一:选取基本操作
步骤二、计算基本操作的执行次数:
2 * N + 10
步骤三、使用大O渐进表示法化简:
主要步骤:省略常数和低项,只保留最高项,最高项如果有系数,把系数去掉
化简结果:
N
所以 func2 的时间复杂度为:
O(N)
练习二、
步骤一、选取基本操作
步骤二、计算基本操作的执行次数:(即循环的次数)
0~100 — 循环执行了 100 次
步骤三、使用大O渐进表示法化简,因为执行次数是常数,直接使用O(1)表示即可
O(1)
练习三、(冒泡排序)
步骤一、选取基本操作
步骤二、计算基本操作的执行次数
内层循环执行的次数:end - 1 次,由于 end 是等于 array.length ,该式子可以等于 array.length - 1
外层循环执行的次数:array.length 次
array.length 是数组的长度,即冒泡排序问题的规模,可以用 N 表示
基本操作的执行次数为:
N * (N -1)
步骤三、使用大 O 渐进表示法化简
展开上式:
N * N - N
省略低项,只保留高项,所以一次项 N 被省略,最终化简为:
N * N
最终的时间复杂度为 :
O(N * N)
练习四、
步骤一、选取基本操作,循环中的两个语句
步骤二、计算基本操作的执行次数
第一个循环:执行了 M 次
第二个循环:执行了 N 次
总次数为:
M + N
步骤三、利用大 O 表示法进行化简
上述式子没有常数,并且 M 和 N 都为一次项(且不是常数),所以时间复杂度就是它本身
O(M + N)
练习五、(二分查找)
步骤一、针对二分查找,最坏情况下是查找序列的最后一个元素(支持二分查找的序列只能是有序的序列)
方法一、可以自己利用左右两边的坐标 / 2 得中间元素重复比较,最后算出来比较的次数,这里不展开,自行计算
方法二、二分查找树,元素位于数的层数就是查找的次数
给定三个序列观察规律:
①、查找 4 的位置
2 4
②、查找 8 的位置
2 4 6 8
③ 、查找 12 的位置
2 4 6 8 9 10 11 12
综合上述的三次查找分析规律:👇
- 序列 2 个元素查找次数:2
- 序列 4 个元素查找次数:3
- 序列 2 个元素查找次数:4
😲 最终发现序列的元素个数和查找次数存在这样的关系:
查找次数 = log2N + 1 (2为底数)
把这样的公式利用大 O 表示法进行化简后 (常数 1 省略):
log2N
最终二分查找的时间复杂度:
O(log2N) 或者可以写成 O(logN)
练习六、递归求阶乘
首先,需要明确一个点:
递归的时间复杂度 = 递归的次数 * 每次递归执行的次数
分析递归的终止条件为:
N < 2
即当 N 等于 1 的时候递归终止,所以可以得出递归的次数为:
N
每次三目运算符执行的次数为:
1
最终时间时间复杂度为:
O(N)
练习六、斐波那契数列递归
递归执行的次数:
由于计算的时间复杂度都为最坏情况下的,所以这里默认每一次递归的层数都是满的
- 第一层递归次数为:1
- 第二层递归次数为:2
- 第三层递归次数为:4
- 第四层递归次数为:8
- …………………………
😉 我们发现每一层的个数为:
2 ^ (层数-1)
😐 所以总的递归执行次数为一个等比数列求和,最后结果为:
2 ^ n + 1
最终的时间复杂度:
O(2 ^ n)
练习七、冒泡排序的空间复杂度
数组的规模是固定的,交换时的中间变量仅仅只有一个,所以不存在变量规模随着问题规模增大而增大的现象
所以空间复杂度:
O(1)
练习八、计算 fibonacci 的空间复杂度
这里存储菲波那切数值的数值随着程序进行不断的在增大,所以这里存在变量规模随着问题规模增大而增大的现象
所以空间复杂度:(就是数组的大小,把常数 1 省略)
O(N)
练习九、递归的空间复杂度
😈 递归多少次函数就会开辟多少内存,所以这里存在变量规模随着问题规模增大而增大的现象
😇 开辟的内存空间即递归的次数 :N
所以这里的空间复杂度:
O(N)
以上是相关时间复杂度和空间复杂度的解析,如果有任何疑问,随时评论留言私信都可以,尽全力为大家解决,谢谢大家的支持
💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞