全面解读算法时间复杂度

衡量一个算法优劣的标准

在信息学奥赛中,一个算法的优劣主要从算法的执行时间和所需要占用的存储空间两个方面衡量。

由于近年来信息学奥赛比赛题目中空间要求逐渐增大,因此,更多的是关心程序的时间复杂度。

当追求一个较好的时间复杂度时,可能会使空间复杂度的性能变差,即可能导致占用较多的存储空间。反之,当追求一个较好的空间复杂度时,可能会使时间复杂度的性能变差,即可能导致占用较长的运行时间。

空间复杂度

空间复杂度 是对一个算法在运行过程中临时占用存储空间大小的量度。

比如int a[100];所占用的内存空间大小 就是10048bit 。一个长度为n 的数组对应的空间复杂度为O(n) 。

需要注意的是,一段程序运行的时间复杂度,不可能低于他的空间复杂度。

时间复杂度

时间复杂度表示程序运行占用时间的多少,是评估算法效率的重要指标。一般表示为关于n 的某个函数。其中n 往往对应输入数据的规模,用 T(n)表示。

若有某个辅助函数f(n) ,存在一个正常数c 使得 f(n)*c>=T(n)恒成立。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。
时间复杂度常用大O 符号表述,不包括这个函数的低阶项和首项系数。

例如:如果一个算法对于任何大小为n (必须比n0 大)的输入,它至多需要5n3+3n 的时间运行完毕,那么它的渐进时间复杂度是O(n3) 。

理解:时间复杂度就是预估程序运行时的操作次数

常见时间复杂度

在这里插入图片描述
从运行效率来看:
O(1)>O(loglogn)>O(logn)>O((logn)2)>O(n1/2)>O(n2/3logn)>O(n)>O(nlogn)>O(n2)>O(n3)>O(2n)>O(3n)>O(n!)>O(nn)

根据输入数据规模预估算法

在这里插入图片描述

算法时间复杂度分析技巧

一般来说我们预估程序的时间复杂度主要考察的是循环和递归,其他的操作可以忽略不计。

时间复杂度分析的基本策略:从内向外分析,从最深层开始分析。如果遇到函数调用,要深入函数进行分析。
1、O(n)时间复杂度

void aFunc(int n) { 
  for(int i = 0; i < n; i++) {     // 循环次数为 n 
   cout << "Hello, World!" << endl;   // 循环体时间复杂度为 O(1) 
}

这段程序的循环运行次数为 n次,每次输出看作O(1) ,因此时间复杂度为 O(n)。

2、O(n2)时间复杂度

void aFunc(int n) { 
  for(int i = 0; i < n; i++) {     // 循环次数为 n 
    for(int j = 0; j < n; j++) {    // 循环次数为 n 
     cout << "Hello, World!" << endl;   // 循环体时间复杂度为 O(1) 
   } 
 } 
}

这段程序的外层循环运行次数为 n次,内层循环运行次数也是 n次,每次输出看作O(1) ,总共输出了n2行,因此时间复杂度为O(n2) 。

void aFunc(int n) { 
  // 第一部分时间复杂度为 O(n2) 
  for(int i = 0; i < n; i++) { 
    for(int j = 0; j < n; j+=2) { 
     cout << "Hello, World!" << endl; 
   } 
 } 
  // 第二部分时间复杂度为 O(n) 
  for(int j = 0; j < n; j++) { 
   cout << "Hello, World!" << endl; 
 } 
}

第一段程序会执行n2/2 次,第二段程序会执行 n次,共执行n2/2+n 次,因此时间复杂度为O(n2)

3、O(n1/2)时间复杂度

void aFunc(int n) {
  for (int i = 1; i * i <= n; i++)
   cout << "Hello, World!" << endl;
}

当 i>n1/2时,会退出循环。复杂度O(n1/2) 。

4、O(logn)时间复杂度

void aFunc(int n) {
  for (int i = 1; i <= n; i += i)
   cout << "Hello, World!" << endl;
}

i的取值每次会翻倍,因此程序只会执行log(n) ,复杂度为O(logn) 。对数复杂度的程序执行效率很
高,哪怕n=1018 ,也只会执行60 多次.

5、主定理
主定理是分治算法分析中非常重要的定理。

如,我们要处理一个 规模为 n 的问题通过分治,得到 a 个规模为 n/b的问题,分解子问题和合并子问题的时间是 f(n):

T(n) = aT(n/b)+f(n)

在上面这个式子里,我们得要求 a >=1, b> 1 (如果 b=1 时,递推无意义),f(n) 是渐进意义上的正数。

回顾一下,a 和 b 的含义:
(1)a 个子问题,即 a 是原问题分为子问题的个数;
(2)每个子问题的规模是n/b;
(3) 分治算法共三部分,分治合,而 f(n) 就是分+合的时间。

假设f(n)=O(nd)
在这里插入图片描述
例如:
(1)T(n)=4T(n/2)+f(1)乐高铺积木
a=b=4,logba=log44=1;
f(n)=O(nd)=f(1),得到d=0;
所以符合上述第2种情况,因此,T(n)=f(n)

(2)T(n)=T(n/2)+f(1)二分查找
a=1,b=2;logba=log21=0;
f(n)=O(nd)=f(1),得到d=0;
符合第3种情况,因此,T(n)=O(logn)

(3)T(n)=16T(n/4)+n
a=16,b=4;logba=4
f(n)=O(nd)=f(n),得到d=1;
符合第2种情况,因此,T(n)=O(n4)

(4)T(n)=3T(n/2)+n2
a=3,b=2,logba=log23
f(n)=n2,则d=2
符合第1种情况,T(n)=O(nd)=O(n2)

对应比赛题目

此类问题主要体现在阅读程序过程中,对程序时间复杂度进行分析;或者选择题部分;
1、若某算法的计算时间表示为递推关系是T(N)=2T(N/2)+N log N,T(1)=1则该算法的时间复杂度为(C)
A、O(N)
B、O(NlogN)
C、O(N(logN)^2)
D、O(N^2)
答案解析:一共有logn 层, 每一层的时间复杂度是nlogn, 故总的时间复杂度为:O(nlogn*logn) = O(n(logn)^2)

2、假设某算法的计算时间表示为递推关系式T(n)=2T(n/4)+sqrt(n),T(1)=1,则算法的时间复杂度为©
A、O(n)
B 、O(sqtr(n))
C、O(sqrt(n)logn)
D、O(n^2)
答案解析:根据主定理T(n) = a×T(n/b)+f(n),f(n)=sqrt(n),则f(n)复杂度为O( nd),d=1/2;又a=2,b=4,logba=log42==d;所以,T(n) = O(nd(logn) ).

3、某算法的计算时间表示为递推关系式T(n)=T(n-1)+n(n为正整数)及T(0)=1,则该算法的时间复杂度为(D)
A、O(logn)
B、O(nlogn)
C、O(n)
D、O(n2)
答案解析:T(n)=T(n-1)+n=T(n-2)+(n-1)+n=T(n-3)+(n-2)+(n-1)+n…;可以推导出T(0)+1+2+…+(n-2)+(n-1)+n=1+1+2+…+(n-2)+(n-1)+n=1+(n+1)*n/2。所以为 O(n²),选D。

4、104、T(n)表示某个算法输入规模为n时的运算次数。如果T(1)为常数,且有递归式T(n)=2*T(n/2)+2n,那么T(n)=(B).
A、O(n)
B、O(nlogn)
C、O(n2)
D、O(n2logn)
答案解析:根据主定理T(n) = a×T(n/b)+f(n),f(n)=2n,则f(n)复杂度为O( nd),d=1;又a=2,b=2,logba=log22==d;所以,T(n) = O(nd(logn) ).

5、如果对于所有规模为n的输入,一个算法均恰好进行(A)次运算,我们可以说该算法的时间复杂度为O(2n).
A、2(n+1)
B 、3n
C、n*2n
D、2(2n)

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信奥教练Andy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值