【零基础学算法第一讲】算法的时间复杂度

计算机领域中,无论是升学还是面试,算法都是一个绕不过的坎儿。有的学校、公司对于算法这部分的得分比重占了很大一部分。所以算法的学习非常必要。

这讲我们通过一个例子来说明什么是算法,什么是算法的时间复杂度,以及如何分析算法的时间复杂度。辣么我们就开始吧↓↓↓

来看一个题目

明明的随机数:明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了 N N N个1到1000之间的随机整数( N ≤ 100 N≤100 N100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。

这题我们可以使用统计的思想:设置一个数组rec[n],然后从前往后遍历所有学号,每遇到一个学号i就令rec[i] = 1。最后遍历一遍数组rec,只要值为1就是出现过的学号。【算法①】

这种统计思想在排序中很常见,感兴趣的读者可以搜一下“桶排序”或者“基数排序”

什么是算法

用计算机解决问题的方法。它是解决一个问题准确而完整的描述。

我们上面对于问题的描述【算法①】就是一个算法(只不过没有用具体的语言表示出来)

时间复杂度:衡量算法好坏的主要指标之一

时间复杂度衡量一个算法使用时间的多少。一个算法的时间复杂度越低,它跑一次需要的时间就越短,这个算法就越优秀。所以我们要在解出问题的前提下,尽可能地优化我们算法的时间复杂度。即:同一个问题可以有不同的算法,它们可能消耗不同的时间,我们应该取耗时最短的那一个

为什么时间复杂度重要

因为一个算法的时间复杂度代表我们需要等待多长时间这个算法才能够跑完,我们才能得到问题的解。

在一款软件中,某个算法很可能只是整个系统中一个很小的部分,如果这个部分使用的时间太长,可能导致整个软件响应速度低下,用户体验差等问题。

数据分析的时候我们需要跑大量的数据,这时候一个优秀的算法就可以节省大量的时间。而一个时间复杂度太高的算法就可能耗费几天几周甚至几年的时间(当然跟硬件也有关系)

所以在各种面试题中都会对算法的时间复杂度做一定的限制。

如何分析算法的时间复杂度

我们康康刚才那个问题(明明的随机数),假设我们手上随机出来的学号为1 5 7 1 6 1 4 5 7 。我们要做两件事:去重和排序。如果我们先从第一个数1开始,向后查找所有的1,如果找到就删去。再从第二个数5开始向后查找所有的5,找到就删去。(为了节省时间,使用一个初值为0的del[n]数组,被删除的元素i在数组中记为del[i] = 1)如此这般做完以后再排序,也是可以解出这道题目的。但是时间上就比前文使用的方法要慢得多。【算法②:先去重再排序】

算法②时间复杂度分析
去重:对于每一个数都要遍历一遍其后所有数,平均每个数需要遍历 n 2 \frac{n}{2} 2n 个数,而一共有n个数需要做遍历,二者相乘得到这个算法的时间复杂度,表示为: O ( 1 2 n 2 ) = O ( n 2 ) O(\frac{1}{2}n^2) = O(n^2) O(21n2)=O(n2)(因为当n足够大的时候,常数的影响可以忽略不计,所以时间复杂度通常省略掉前面的常数)

排序:最小时间复杂度是 n l o g 2 n nlog_2n nlog2n
(具体怎么实现的篇幅所限这里不予介绍,感兴趣可以看看“快速排序”,很多语言也有直接的排序函数可以使用,其时间复杂度都是最优的 n l o g n nlogn nlogn)这里的 l o g n logn logn指的是对数级别的时间复杂度,底数默认为2常常省去不写。

这里去重排序是并列(互不影响)的操作。我们取最大的一个操作作为其整个算法的时间复杂度。法②的时间复杂度是 O ( n 2 ) O(n^2) O(n2)

当然我们也可以先做排序再做去重:将手上的数1 5 7 1 6 1 4 5 7做一遍排序以后得到:1 1 1 4 5 5 6 7 7,然后从第二个数开始,对于每个数,看一遍它前面的数是否与它相等,若相等则将它删掉(同样若想要节省时间,可以使用一个del[n]数组,记录删除的元素)【算法③:先排序再去重】

算法③时间复杂度分析

排序:同上,最小时间复杂度是 n l o g 2 n nlog_2n nlog2n

去重这个步骤在排序的基础上只需要扫一遍整个数组就行,所以是 O ( n ) O(n) O(n)级别的时间复杂度。因为 O ( n ) < O ( n l o g n ) O(n)<O(nlogn) O(n)O(nlogn),二者并列的时候我们取最大的作为其时间复杂度。法③的时间复杂度是 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

算法①时间复杂度分析:算法①只需要遍历一遍整个数组即可,所以算法①的时间复杂度是 O ( n ) O(n) O(n)(如果包括输出学号的话,遍历两遍,但常数忽略不计所以仍然是线性时间复杂度)

常见时间复杂度大小比较

O ( 1 ) < O ( l o g n ) < O ( n ) < O ( n ) < O ( n l o g n ) < O ( n 2 ) < O ( n 3 ) < O ( C n ) < O ( n ! ) < O ( n n ) O(1)<O(logn)<O(\sqrt{n})<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(C^n)<O(n!)<O(n^n) O(1)<O(logn)<O(n )<O(n)<O(nlogn)<O(n2)<O(n3)<O(Cn)<O(n!)<O(nn) 这里 C C C为常数, n n n为算法的输入规模

它们的称呼,了解即可:我们将 O ( 1 ) O(1) O(1)称作常量级, O ( l o g n ) O(logn) O(logn)称作对数级, O ( n ) O(n) O(n)称作线性级, O ( C n ) O(C^n) O(Cn)称作指数级, O ( n ! ) O(n!) O(n!)阶乘级。一般线性级以前的算法都是很优秀的算法。而到了指数级以后就是很糟糕的了。

常用的刷题网站

本系列选讲的例题都有对应的测评网站,网址将会附在每道题上面。读者可以在看完博客以后链接到对应的网站提交自己的代码巩固,网站以牛客为主,洛谷codeforces都有涉及。

猜你喜欢

转载自blog.csdn.net/weixin_44559752/article/details/108218611
今日推荐