算法复杂度分析的那些事

我是自动化专业的应届研究生,最终拿到了tplink、华为、vivo等公司的ssp的offer,分享自己学习过的计算机基础知识(C语言+操作系统+计算机网络+linux)以及数据结构与算法的相关知识,保证看完让你有所成长。
欢迎关注我,学习资料免费分享给你哦!还有其他超多学习资源,都是我自己学习过的,经过过滤之后的资源,免去你还在因为拥有大量资源不知如何入手的纠结,让你体系化学习。
在这里插入图片描述
对于一个算法来说,我们如何评价它的好坏呢?一般来说就是通过程序解决问题的时间和空间。现在的计算机空间效率一般已经不是关注的重点了,但是时间效率仍然是算法关注的重点。而考查一个程序的运行时间,就需要将程序每次执行的操作表示成输入规模的函数。这就是时间复杂度分析。时间复杂度的分析也是算法面试中常考的问题,经过最近的学习,总结如下。

什么是大O记法

举几个例子来说,O(f(n))是一个集合,表示的是所有函数的增长趋势小于等于f(n)的函数集合。比如n属于O(n^2),500n+10属于O(n ^ 2).

对于定义来说就是,对于一个函数g(n)属于O(f(n))中,表示如下的公式:
g ( n ) ∈ O ( f ( n ) ) g(n)\in O(f(n)) g(n)O(f(n))
它表示的条件是:对于足够大的n,,g(n)的上界由f(n)的常数倍所确定,也就是说,存在大于0的常数c和非负数n0,使得:对于所有的n大于等于n0时,g(n)都是小于等于cf(n)的。

在这里插入图片描述
比如前面所说500n+10小于等于510n^2.它的c=501。

大O记法的一些特性

1.如果 t 1 ( n ) ∈ O ( g 1 ( n ) ) t_1(n)\in O(g_1(n)) t1(n)O(g1(n)) 并且 t 2 ( n ) ∈ O ( g 2 ( n ) ) t_2(n)\in O(g_2(n)) t2(n)O(g2(n)),那么 t 1 ( n ) + t 2 ( n ) ∈ O ( m a x g 1 ( n ) , g 2 ( n ) ) t_1(n)+t_2(n)\in O(max{g_1(n),g_2(n)}) t1(n)+t2(n)O(maxg1(n),g2(n))

这也是我们在计算时间复杂度中最常使用到的,比如一个算法的时间复杂度是 n^2+n+2,根据上面的定理,我们可以说它的大O时间复杂度是O(n ^ 2)。

2.对于常数的运行时间,对于大O表示法来说都是O(1)。

3.系数对于大O表示法是没有用的,比如n^2和1000n ^2来说,它们的大O记法是一样的,因为通过定义可以知道,系数其实本质上就是定义中的c,所以它们的大O记法都是O(n ^2)。

常见的时间复杂度
  1. 对于顺序结构的程序执行,它的时间复杂度就是O(1).
int a=10;
int b=5;

上面程序虽然执行了两步,但对于大O表示法来说,都是O(1),因为2相当于是系数,可以去掉。

  1. 下面这个循环结构的时间复杂度是O(n)
for(int i=0;i<n;i++)
{
    int b=10
}
  1. 下面这个程序就是O(logn)的时间复杂度
int count=1;
while(count<n)
{
	count=count*2;
}

由于每次执行count扩大两倍,那么就是2^ x=n,可以解得x=log以2为底的n的对数,所以时间复杂度就是O(logn)

  1. 双重循环就是O(n^2)的时间复杂度
for(int i=0;i<n;i++)
{
   for(int j=0;j<n;j++)
   {
       //
   }
}
非递归算法的时间复杂度分析

以查找数组中的最大值程序为例,分析计算一个非递归程序时间复杂度是如何计算的。

int MaxElement(int *A,int n)
{
	int maxval=A[0];
	for(int i=0;i<n;i++)
	{
		if(A[i]>maxval)
		{
			maxval=A[i];
		}
	}
	return A[i];
}

可以看到,这个问题的输入规模是数组元素的个数决定的。由前面的学习可以知道,一个程序的时间复杂度是由程序之中大O最大部分决定的,所以只需要计算最大值就可以了,这个程序中的最大值是由for循环部分决定的。for循环内部进行了一步的比较操作,那么对于i从0到n-1,一共进行了n-1次比较,那么整个程序执行的次数就是:
C ( n ) = ∑ i = 0 n − 1 1 = n − 1 = O ( n ) C(n)=\sum_{i=0}^{n-1}1=n-1=O(n) C(n)=i=0n11=n1=O(n)
所以时间复杂度是O(n),这个分析也证明了前面所说的for循环的时间复杂度是O(n).

非递归的时间复杂度分析的步骤如下:

1)首先找到问题的输入规模在哪里,例如本例的n

2)找出算法的基本操作(一般是最内层的循环)

3)建立一个算法基本操作的求和表达式,利用数学知识得到它的和

4)利用大O的一些准则简化表达式,得到最终的大O时间复杂度分析结果。

bool uniqueElements(int *A,int n)
{
	for(int i=0;i<n-1;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			if(A[i]==A[j])
			{
				return false;
			}
		}
	}
	return true;
}

我们根据上面的一个算法,找出一个数组中是否包含重复元素,来实践一下刚才所说的分析方法,首先找到输入规模为n,但是这个算法如果在中间出现了相同元素,就结束了,所以说不仅仅取决于n,还取决于数组中数据的情况,这里谈论一下最坏的情况,就是遍历了整个数组。

那么此时的输入规模就是n,找到关键的执行步骤,双重循环中的判断语句,每次执行一次。在内循环之中j在i+1和n-1之间的每一个值都会比较一次。在外循环中,i从0到n-2的每个值,都会重复上面的过程一遍。因此可以得到:
C w o r s t ( n ) = ∑ i = 0 n − 2 ∑ j = i + 1 n − 1 1 C_{worst}(n)=\sum_{i=0}^{n-2}\sum_{j=i+1}^{n-1}1 Cworst(n)=i=0n2j=i+1n11
此时就考验数学了。首先将内部的j循环展开。
C w o r s t ( n ) = ∑ i = 0 n − 2 ∑ j = i + 1 n − 1 1 = ∑ i = 0 n − 2 [ ( n − 1 ) − ( i + 1 ) + 1 ] = ∑ i = 0 n − 2 ( n − 1 − i ) = ∑ i = 0 n − 2 ( n − 1 ) − ∑ i = 0 n − 2 i C_{worst}(n)=\sum_{i=0}^{n-2}\sum_{j=i+1}^{n-1}1=\sum_{i=0}^{n-2}[(n-1)-(i+1)+1]=\sum_{i=0}^{n-2}(n-1-i)=\sum_{i=0}^{n-2}(n-1)-\sum_{i=0}^{n-2}i Cworst(n)=i=0n2

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值