复杂度分析相关

本文深入讲解算法复杂度的概念,包括时间复杂度与空间复杂度,介绍复杂度记号如O、Ω、Θ,并通过实例解释如何计算复杂度,涉及积分估计、主定理及均摊分析等方法。

一.复杂度的定义.

复杂度:复杂度是衡量一个代码质量的重要指标,主要分为时间复杂度空间复杂度,其中又以时间复杂度更为重要.

复杂度记号:一个算法XXX的复杂度上界O(X)O(X)O(X)定义为XXX的运行总量多项式只保留最高次项并去掉常数后的值,例如:
O(3n2+5n+7)=O(n2)O(78n+10log⁡3.4n)=O(n)O(5n2log⁡3.53(100n))=O(n2log⁡3n)O(2n+2+8n7)=O(2n) O(3n^{2}+5n+7)=O(n^{2})\\ O(7\sqrt{8n}+10\log_{3.4} n)=O(\sqrt{n})\\ O(5n^{2}\log_{3.5}^{3}(100n))=O(n^{2}\log^{3} n)\\ O(2^{n+2}+8n^{7})=O(2^{n}) O(3n2+5n+7)=O(n2)O(78n+10log3.4n)=O(n)O(5n2log3.53(100n))=O(n2log3n)O(2n+2+8n7)=O(2n)

当然有些时候常数对代码的效率影响也很大,但在复杂度计算中不予考虑.

其实记号OOO表示的只是一个上界,也就是说一个算法的复杂度为O(n2)O(n^2)O(n2),那么它的复杂度也可以被写为O(n3)O(n^3)O(n3).

再来一些实例解释一下吧,比如说下面这串代码:

int ans=0;
for (int i=1;i<=n;i+=5)
  for (int j=n;j>=10;--j)
    for (int k=1;k<=n;k+=2) ++ans;

这串代码的时间复杂度就是O(n3)O(n^3)O(n3).

在比如说下面这串代码:

int ans=0;
for (int i=1;i<=n;i<<=1)
  for (int j=2;j<1<<i;++j)
    for (int k=4;k*k<=n;++k) ++ans;

这串代码的时间复杂度就是O(2nnlog⁡n)O(2^{n}\sqrt{n}\log n)O(2nnlogn).

除此之外,复杂度还有记号例如Ω(n)\Omega(n)Ω(n)Θ(n)\Theta(n)Θ(n),其中Ω\OmegaΩ表示下界,Θ\ThetaΘ表示上下都有界.


二.积分估计计算时间复杂度.

若对于某一个和式:
∑i=1nf(i) \sum_{i=1}^{n}f(i) i=1nf(i)

其中f(x)f(x)f(x)是一个多项式,但这个东西并不好估计它的具体值,我们该如何计算呢?

有一个非常简单的方法,直接将这个和式看成积分的离散表示,然后直接用积分算复杂度.

由于复杂度计算的只是大概值,所以这样算是没有关系的.

也就是说:
O(∑i=1nf(i))=O(∫1nf(i)di) O\left(\sum_{i=1}^{n}f(i)\right)=O\left(\int_{1}^{n}f(i)\mathrm{d}i\right) O(i=1nf(i))=O(1nf(i)di)

一个经典的例子是计算如下和式在复杂度表示中的值:
O(n∑i=1n1i)=O(n∫i=1n1idi)=O(nlog⁡n) O\left(n\sum_{i=1}^{n}\frac{1}{i}\right)=O\left(n\int_{i=1}^{n}\frac{1}{i}\mathrm{d}i\right)=O(n\log n) O(ni=1ni1)=O(ni=1ni1di)=O(nlogn)



三.主定理.

对于一个递归函数:
T(n)=aT(nb)+f(n) T(n)=aT(\frac{n}{b})+f(n) T(n)=aT(bn)+f(n)

如何计算O(T(n))O(T(n))O(T(n))呢?

主定理:对于T(n)=aT(nb)+f(n)T(n)=aT(\frac{n}{b})+f(n)T(n)=aT(bn)+f(n),则有:
O(T(n))={O(nlog⁡ba)∃k>0⇒f(n)=O(nlog⁡ba−k)O(nlog⁡balog⁡k+1n)∃k>0⇒f(n)=O(nlog⁡balog⁡kn)O(f(n))∃k>0⇒f(n)=Ω(nlog⁡ba+k) O(T(n))= \left\{\begin{matrix} O(n^{\log_{b}a})&\exists k>0\Rightarrow f(n)=O(n^{\log_{b}a-k})\\ O(n^{\log_{b}a}\log^{k+1}n)&\exists k>0\Rightarrow f(n)=O(n^{\log_{b}a}\log^{k}n)\\ O(f(n))&\exists k>0\Rightarrow f(n)=\Omega(n^{\log_{b}a+k}) \end{matrix}\right. O(T(n))=O(nlogba)O(nlogbalogk+1n)O(f(n))k>0f(n)=O(nlogbak)k>0f(n)=O(nlogbalogkn)k>0f(n)=Ω(nlogba+k)

有了主定理我们就可以算很多分治算法的复杂度了,例如:
T(n)=2T(n2)+O(1)⇒O(T(n))=O(n)T(n)=T(n2)+O(1)⇒O(T(n))=O(log⁡n)T(n)=2T(n2)+O(nlog⁡n)⇒O(T(n))=O(nlog⁡2n)T(n)=2T(n2)+O(n2)⇒O(T(n))=O(n2) T(n)=2T(\frac{n}{2})+O(1)\Rightarrow O(T(n))=O(n)\\ T(n)=T(\frac{n}{2})+O(1)\Rightarrow O(T(n))=O(\log n)\\ T(n)=2T(\frac{n}{2})+O(n\log n)\Rightarrow O(T(n))=O(n\log^2 n)\\ T(n)=2T(\frac{n}{2})+O(n^2)\Rightarrow O(T(n))=O(n^2) T(n)=2T(2n)+O(1)O(T(n))=O(n)T(n)=T(2n)+O(1)O(T(n))=O(logn)T(n)=2T(2n)+O(nlogn)O(T(n))=O(nlog2n)T(n)=2T(2n)+O(n2)O(T(n))=O(n2)


四.均摊分析.

有些时候,一个算法有nnn步,处理每一步的时候复杂度可能达到O(n)O(n)O(n),但其总复杂度却可以保证O(n)O(n)O(n),是不是非常神奇?

是的,确实有这种算法,而且还有不少,例如KMP就是其中最经典的一种.

那么它的复杂度是怎么保证的呢?有一个叫均摊复杂度方法可以证明.

例如KMP的时间复杂度分析过程:我们注意到KMP的每执行一次j=next[j]j=next[j]j=next[j]都会使得jjj至少−1-11,而总共nnn步中jjj每步最多只能+1+1+1,且jjj无论何时都是>0>0>0的,所以它的复杂度是O(n)O(n)O(n)的.

这就是一种均摊时间复杂度的方法.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值