☀前言:我们再编写程序时,不同的人有不同的思路,算法。那么如果需要比较谁的代码更好,使用哪种算法效率更高,我们一般会从代码程序的速率和所占空间去考虑。这时我们就需要使用一种方法描述程序运行的时间复杂度(运行快慢),空间复杂度(运行程序所占用的内存空间)
目录
引入案例
分析时间,空间复杂度
我们再次推广
以下是大O表示法常见的复杂度表示
假如你和你的朋友再玩猜数字游戏,游戏规则如下
你的朋友在数字1到100中选出一个数字,那么你在不知情的情况下去猜这个数字是多少,你的朋友根据你猜的数字给出提示,指出你猜的数字是大了还是小了,不限猜的次数。
✏ 这是一个简单的游戏,最终你都可以猜到答案,但是那要怎么猜呢?
如果你从1开始逐个往上猜
♂️你:1
♂️朋友:小了
♂️你:2
♂️朋友:小了
......
♂️你:68
朋友:猜对了
这是什么查找方法呢?
说不好听的就是傻找,说得好听一些就是遍历
对于这种傻找,最理想的情况是你朋友选了1,你也正好从1开始,最糟糕的情况就是你朋友选了100,你还从1开始逐个往后猜,那傻子才玩这种游戏。
✏ 那么有没有更好的办法快速猜到这个数字 ?
当然有,就是我们常说的二分法,根据二分法,我们可以这么猜
假如你朋友选了69
♂️你:50(1到100的中间数字)
♂️朋友:小了
♂️你:75(50到100的中间数字)
♂️朋友:大了
♂️你:63(75到100的中间数字)
♂️朋友:小了
♂️你:69(63到75的中间数字)
朋友:猜对了
使用二分法糟糕的情况是需要猜次,因为每次我们都是猜中间的数字,如果猜错了也没事,猜错了我们也可以排除一半的情况,n = 100,那么我们最多需要猜7次。比傻找最糟糕的情况少猜了93次。
对于上述的案例,我们如何表示傻找和二分法的时间复杂度,和空间复杂度呢?
写出代码程序然后运行计算得出结果需要多少秒,占用多少m内存?,当然不是。
我们使用大O表示法表示程序的空间复杂度和时间复杂度
写作:O(x),x表示时间或空间复杂度也称操作数
值得注意的是,分析程序,算法的复杂度是我们考虑的都是最糟糕情况下的复杂度
对于案例
傻找的最糟糕情况为猜100次
那么傻找的时间复杂度为O(100)= O(1)
我们假设记录每次猜的数字,最糟糕情况为猜100次也就需要记录100个数字
那么空间复杂度为O(100)= O(1)
---------------------------------------------------------
二分法的最糟糕情况为猜7次
那么二分法的时间复杂度为O(7)= O(1)
我们假设记录每次猜的数字,最糟糕情况为猜77次也就需要记录7个数字
那么空间复杂度为O(7)= O(1)
✏ 为什么O(100)= O(7)= O(1)?
因为在daO()表示法中,我们把所有的O(常数)均表示为O(1)
现在我们推广案例,假如从1到n猜数字。(一般情况下n很大)
那么
傻找的时间复杂度为O(n)
空间复杂度为O(n)
--------------------------------------------
二分法
的时间复杂度为O()
空间复杂度为O(n)
假设你和朋友玩猜数字先在1到n猜,然后朋友决定加大难度再从1到2n中选一个数字再猜一次,同样记录你每次猜的数字,不限猜的次数。
那么对于两次游戏
傻找的最糟糕情况为:
第一次需要猜n次
第二次需要猜2n次
傻找的时间复杂度为O(3n)= O(n)
空间复杂度为O(3n)= O(n)
----------------------------------------------------
二分法查找的最糟糕情况为:
第一次需要猜次
第二次需要猜次
时间复杂度为O()= O()
空间复杂度为O()= O()
✨接着朋友想再次提高难度
假设你和朋友玩猜数字先在1到n猜,你猜对后朋友将正确数字分成n等份(可能变成小数)再选一个数字让你再猜一次,同样记录你每次猜的数字,但是猜对第一次后不在记录(n等分后的数字不再记录),不限猜的次数,但是这次朋友不会提醒你数字大了还是小了。
(说白了他就是不想玩了,让你单纯找着玩,猜数字变成了找数字)
那么对于两次猜数字
傻找的最糟糕情况为:
因为朋友不在提醒,所以你需要找出所有结果。
先遍历n个数字,再“猜”第1个数字的时候又将其分为n个数字,那你还要再“猜”n次。如此进行下去,那么最糟糕的结果需要寻找n*n = 次。
这时
傻找的时间复杂度为O()
因为但是猜对第一次后不在记录你猜的数字(n等分后的数字不再记录),所以
空间复杂度为O(n)
对于二分法,因为朋友不会提醒你数字大了还是小了。
所以你无法使用二分法查找
O(n) | 也叫线性时间 | 一般是一次简单查找 |
O() | 对数时间 | 常见有二分法 |
O() | 常见有快速排序等 | |
O() | 常见于两层的for循环 | |
O(n!) | 拥有非常慢的运行速度 | 常见数性结构的遍历 |
复杂度比较
(^表示次方)
这就是平时我们在不靠直觉情况下,计算程序复杂度,判断哪个程序更“好”的方法。