在学一些机器学习模型的时候,经常会听到时间复杂度和空间复杂度的概念,内心不禁问一句,这都什么鬼?(黑人问号脸)于是今天小编终于摆脱了懒癌,下定决心查了下相关的资料,终于弄明白了一些!下面和大家分享一下~
什么叫时间复杂度?简而言之,就是你这段代码执行所需的时间!但是即使是同样的样本在不同的机器上运行时间也可能存在差异,另外你总不能老是让代码先run起来,然后再判断吧?那样效率也太低了,不切实际,需要进行提前判断!因此肯定不能用具体程序运行的时间来表示时间复杂度了,而是要抽象出来!适用于不同的模型!如何抽象呢?简单来说就是程序的运行次数来表示时间复杂度!数学上使用的表示方法则是 大O符号表示法!同时有一点值得注意的是:大O符号表示法并不是用于来真实代表算法的执行时间的,它是用来表示代码执行时间的增长变化趋势的,这个在下面的例子中将体现的会比较好!
三步:
以下形式中时间复杂度逐步提升!其中1-6称为多项式时间,7-8称为指数时间。多项式时间复杂度的算法是有效算法,称为P(Polynomial,多项式)类问题,而指数时间复杂度的算法称为NP(Non-Deterministic Polynomial, 非确定多项式)问题。
首先来看两个法则:
int i = 1;
int j = 2;
++i;
j++;
int m = i + j;
以上代码就是时间复杂度为O(1),即无论代码执行了多少行,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是O(1)。
循环n次,即复杂度为O(n):
for(i=1; i<=n; ++i)
{
j = i;
j++;
}
for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用O(n)来表示它的时间复杂度。
可能大家会有点奇怪,诶,为啥出现个对数呢?这是因为在一些循环中,并不是就执行N次,而是有条件的终止!具体见:
int i = 1;
while(i
在while循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。那执行多少次能达到n呢?假设循环x次之后,i 就为n 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2^n
也就是说当循环 log2^n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(logn)
注:有的地方看到有底数2,有的又没有,应该是一致的!
这个就好理解了,适用于乘法法则!在一个while语句外面套一层执行n次的for循环即可!
for(m=1; m
这个也比较好理解,n次for循环外面再套一层n次for循环!
for(x=1; i<=n; x++)
{
for(i=1; i<=n; i++)
{
j = i;
j++;
}
}
如果将其中一层循环的n改成m,即:
for(x=1; i<=m; x++)
{
for(i=1; i<=n; i++)
{
j = i;
j++;
}
}
那么时间复杂度就变成了 O(m×n)
套3层n次for循环即可!
套k层n次for循环即可!
套n层2次for循环即可!
如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
int i = 1;
int j = 2;
++i;
j++;
int m = i + j;
int[] m = new int[n]
for(i=1; i<=n; ++i)
{
j = i;
j++;
}
产生了一个新的数组m,数据占用的大小为n。这段代码的2-6行,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)
再举个小甲鱼课上说的一个形象化的例子:
举个例子,要判断某年是不是闰年!
方法1:每给一个年份,就可以通过一个算法计算得到是否闰年的结果
方法2:事先建立一个有2050个元素的数组,然后把所有的年份按下标的数字对应,如果是闰年,则此数组元素的值是1,如果不是元素的值则为0。这样,所谓的判断某一年是否为闰年就变成了查找这个数组某一个元素的值的问题 【通过空间换时间】
两种方法比较: