• 递归的时间复杂度你真的懂吗?不是所有的二分递归都是logn级别


    本篇文章的书写灵感来源于【代码随想录】,自己写东西纯粹只是给自己看,而且我写的东西估计只有我自己才能看懂,laugh@Hygge。

    首先说明一下,在我很长一段时间这样以为,二分递归这一部分的时间复杂度肯定是O(log n),但是我实在太天真了 :(

    以下通过举例说明说明情况:计算xn的简单题

    最容易想到的O(n)算法代码直接略过,将x一个一个依次乘起来,这种方法在面试官看来,简直就是violence。 

    接下里我们想想还有其他方法吗?比如,万能的缩小时间复杂度的递归,这样会有如下的思路

    想到:利用二分进行递归?哇塞,感觉发现了新大陆,please No talking,show me UR code!

    1     function (int x, int n){
    2         if (n == 0):
    3             return 1
    4         if (n % 2 == 1): # 判奇偶性
    5             return function(x, n / 2) * function(x, n / 2) & x
    6         else:
    7             return function(x, n / 2) * function(x, n / 2)
    8     }

    写出这样的代码,哇塞,天之骄子啊!但是你确定这样的递归缩短了时间复杂度到O(logn)吗?

    我么来分析一波!!!

    在这里,很容易犯的误区来了,你看这个递归树的深度就是logn,所以说时间复杂度就是logn(感觉理直气壮)!但是首先我来说明第一个误区:递归树的深度不是时间复杂度,时间复杂度计算公式应该是「递归的次数 * 每次递归中的操作次数」,在上图中,仔细想一想,每一个node会执行一次乘法,但是然后自顶向上,计算乘法的次数是23(第4层递归操作次数)+22(第3层递归操作次数)+21(第2层递归操作次数)+2(第1层递归操作次数)= 24 - 1(顺便记住计算n层满二叉树的公式,以后面试可能会遇到)。最后:我们发现上面代码执行的递归时间复杂度还是O(n)!所以这个递归和violence的时间复杂度还是一样,而且递归反而还要增加一个系统自动维护地递归栈,切线程,非常耗时!

    在这里,我们根据算法中主定理(T(n) = aT(n /b) + nd)来解释时间复杂度:T(n)= 2T(n/2) + 1(这个加的1是合起来的一次乘法运算),根据主定理,a=2,b=2,d=0,a<bd,所以T(n) = nlogba=nlog22=n,综上所述,T(n) = n (That's way bad!)

    言归正传,那么递归根本没有进行改进呀呀呀,有其他方法改改进吗?哈哈哈哈哈,答案是肯定的,霍纳法则!霍纳法则就是专门解决xn的计算问题滴!

    霍纳法则的代码和矩阵快速幂一样,模板如下:

    1     ans = 1
    2     function (int x, int n){
    3         while n:
    4             if n & 1:
    5                 ans = y * x
    6             x = x * x
    7             n = n > 1 #n/2
    8     }

    这个办法没有用到递归,但是时间复杂度分析真正实现了O(logn),congrats{✿✿ヽ(°▽°)ノ✿}!!!

    好了,写完了,总结一下:

    1.使用递归,时间复杂度绝对不总是O(logn)

    2.霍纳法则求n次方问题

  • 相关阅读:
    结对作业
    读《构建之法》第四章、第十七章
    2016012060+小学四则运算练习软件项目报告
    《构建之法》第1、2、16章阅读随笔
    我与软件
    2016012039+张琪+散列函数的应用及其安全性
    结对作业
    读《构建之法》第四、十七章有感
    2016012039 + 小学四则运算练习软件项目报告
    读书笔记(第1、2、16章)
  • 原文地址:https://www.cnblogs.com/hygge-98-areas/p/14250033.html
Copyright © 2020-2023  润新知