刷算法题?首先要学会基础的算法分析!(递归算法的数学分析和非递归算法的数学分析demo)

前言:

     临近毕业,又到了找工作的黄金期,大家都在准备面试题目,提高自己的技术。这里面有一个很重要的点——算法,在我们学习完算法后,去大量的刷题往往是好的,但是AC之后我们也要学会总结思路,形成自己的套路,这其中分析算法的复杂度就还蛮重要的,至少在我们精益求精想得到最优解的时候(并且在看别人解析的时候),可以给我们很大的帮助。所以和我一起来学习如何分析算法吧!(这里不是单纯的分析时间复杂度哦)。

阅读思路:


一、算法分析的框架

     在说算法分析框架之前,我们是需要了解这几个事情:

  • 输入规模的度量:需要合理的选择参数来表示输入规模(几乎所有的情况我们一眼就能够看出来应该选什么参数作为度量,选择不同可能有略微差别,但不影响我们进行分析)。
  • 运行时间的度量:约定Cop为特定计算机上一个算法基本操作执行时间,C(n)是该算法需要执行基本操作的次数,所以算法程序的运行时间可以约等于T(n) = CopC(n)(我们在下面分析中会用到这个简单的式子)。
  • 增长次数:例如n、logn(默认以2为底)、nlogn、n^2等函数代表增长次数,可以理解为导数代表变化的快慢(也就是我们常说的常数级别、指数级别等名词)。
  • 算法的最优、最差和平均效率:某些时候对于不同的输入(例如我们对数组进行排序,排序执行的时间效率除了和基本的比较或者交换操作有关以外,还和数组本身的序列有关),算法的执行效率并不一致,所以如有必要,我们就要讨论最优、最差和平均效率。

 

分析框架:

     这里首先给出一个大致的框架,其实非递归和递归算法的分析区别是不大的,看整体的框架你就会发现前面几个步骤基本上是一致的。

  1. 算法的时间效率和空间效率都用输入规模的函数进行度量(大部分时候我们都是去讨论时间效率,空间效率很少去讨论,但是在对动态规划以及其它算法进行优化的时候,我们需要考虑空间效率,接近最优解)。
  2. 我们用算法基本操作的执行次数来度量算法的时间效率(基本书上会说for循环里面的那个操作就可以看做是基本操作,其实也就是执行次数最多的操作,因为其它操作太少,所以我们可以用基本操作的执行次数来大致表示时间复杂度,这也就是上面进行约定的原因T=CopC(n)),通过计算算法消耗的额外存储单元的数量来度量空间效率。
  3. 在输入规模相同的情况下,有些算法的效率会有显著差异。对于这样的算法,我们需要区分最差效率、平均效率和最优效率。
  4. 当算法的输入规模趋向于无限大时,它的运行时间(消耗的额外空间)函数的增长次数是我们主要关心的。

     3、4两点是比较模糊的,你肯定是这个表情,所以让我重新复述一遍:

     简单来说,不管是非递归还是递归,我们分析一个算法:

(1)首选都是选择输入规模,

(2)然后找到基本操作

(3)然后判断基本操作的执行次数是否只依赖于输入规模,如果还依赖其它特性,就需要考虑最差、平均和最优效率。

(4)之后如果是非递归我们需要建立求和表达式,得到我们的/(4)如果是递归算法的话,我们需要建立递归关系式并且得到初始条件

(5)增长次数(也就是像这样的形式O(n));(5)然后确定增长次数

     那么我们就一一来看具体的例子吧!


二、非递归算法的数学分析

框架:

  1. 决定用哪个(哪些)参数表示输入规模
  2. 找出算法的基本操作(作为一个规律,它总是位于算法中的最内层循环中)
  3. 检查基本操作的执行次数是否只依赖于规模。如果它还依赖于一些其它的特性,则最差效率、平均销量以及最优效率(如有必要)需要分别研究
  4. 建立一个算法基本操作执行次数的求和表达式
  5. 利用求和运算的标准公式和法则来建议一个操作次数的闭合公式,或者至少确定它的增长次数。

例子:

     验证给定数组中的n个元素是否全部唯一,最简单的算法不就是暴力么?

算法:
UniqueElements(A[0...n-1])
//验证给定数组中的元素是否全部唯一
//输入:数组A[0..n-1]
//输出:如果A中的元素全部唯一,返回true
//      否则,返回false
for i<-0 to n-2 do
	for j<-i+1 to n-1 do
		ifA[i]=A[j] return false
return true
 

     那么我们按照上面框架中的方法一起来分析这个算法把!

(1)基本输入是数组中元素的个数n

(2)基本操作是最内循环里面的比较操作

(3)基本操作除了和输入规模n有关,还和数组中元素的序列有关,例如当第一个和第二个元素相同时,我们直接就结束了算法,此时比较次数C(n)=1。

(4)实际操作中可能我们都只看最差效率Cworst(n),但是这里为了分析我们需要考虑最好、最差和平均效率。

1)最好效率Cbest

     显然我们知道最好就是第一个元素和第二个元素是相同的(不需要关心其它的),那么第一次比较就会返回false,所以这是C(n)=1。

2)最坏效率Cworst

     我们思考一下什么时候比较是最多的,那么第一种情况肯定是没有相同的元素,这样会执行完两层的for循环才会去返回true;第二种情况,就是相同的元素分别在头部和尾部,这样比较的次数也是最多的。现在我们可以建立

 这样的求和表达式,最后近似得到n^2数量级的增长率,这里用Θ来表示。

3)平均效率Cavg

     在实际分析中,我们得到最坏效率就会很开心的走开了,往往平均效率是最烦人的。那么我们一起来看看。

     大前提假设:每一种输入出现的机会是均等的。

  •      首先假设数组里面存在相同的元素:

那么相同元素的输入是以下n种:

     这里我假设相同元素为a==a,所以按照第一个a出现的位置进行分析:

      这里我偷偷懒除法不算了,那么我们就得到Θ(n)的数量级。

     综上,最好、最坏和最差效率,那么我们用O(n^2)来表示此算法的数量级,分析完毕。这里也就是说,一般情况下我们只需要去讨论最坏的情况,所以在大多数分析的时候,我们可以直接用O符号来表示时间复杂度。


三、递归算法的数学分析

框架:

  1. 决定用哪个(哪些)参数作为输入规模的度量标准
  2. 找出算法的基本操作
  3. 检查一下,对于相同输入规模的不同输入,基本操作的执行次数是否可能不同。如果有这种可能,则必须对最差效率、平均效率和最优效率做单独研究
  4. 对于算法基本操作的执行次数,建立一个递推关系以及相应的初始条件
  5. 解这个递推式,或者至少确定它的解的增长次数。

例子:

     求一个正的十进制整数表示为二进制的位数。那么算法有:

算法 BinRec(n)
//输入:一个正的十进制整数n
//输出:n的二进制表示的位数
if n = 1 return 1
else return BinRec(n/2) + 1//n/2这里取下整
 

     现在我们按照上面所说的框架进行分析

(1)输入规模为n的大小

(2)基本操作为BinRec(n/2)+1中的加法

(3)确定基本操作的次数只依赖于输入规模,和其它特性没有关系

(3)那么尝试建立递推关系和初始条件(这里会用到平滑规则定理,它的意思就是在一个非常宽泛的假设下,无论n取何值,它的增长次数与n=2^k时的增长次数是完全相同的):

      最后,我们直接用O(logn)表示我们的时间复杂度即可,上面和这里都没有去讨论空间复杂度,因为我们侧重时间复杂度的分析,但在排序或者动态规划等题目的时候,有些是需要去优化空间复杂度的。

 


总结:

     做一个小小的总结,现在回想一下,如果给你一个算法,你会分析它的时间复杂度吗?非递归怎么做?递归算法怎么做?无非就是找输入规模,找基本操作,判断是否需要进行最好最坏平均效率的分析,要么得到求和表达式,要么得到递推关系,然后利用数学知识计算就可以得到增长次数,得到我们的时间复杂度。

     在上面最后的结果,我没有使用Ω、Θ符号,仅仅用O不是它们不重要,而是在做算法题目的时候,我们往往只是关心最坏的情况而已,所以基本都用O去表示时间复杂度,没有做到那么精确。在非递归算法中,需要进行最好、最坏和平均效率分析的算是比较复杂的,而递归的情况最重要的就是得到递推关系。

     很高兴你可以看到这里,希望下次分析算法的时候,除了可以看到时间复杂度O是多少,还可以想起来利用数学思维去分析每一步骤。额,分析其实感觉还好对吧,写出算法才是最难的呢!之后的博客就更新各种算法啦,让我们一起提高自己的内功吧!

 

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

threecat.up

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

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

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

打赏作者

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

抵扣说明:

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

余额充值