扩展学习:递归式求解时间复杂度的方法——递归树与主定理¶
代入法不做介绍
想要了解更多推荐专栏:
https://zhuanlan.zhihu.com/p/540889250
https://zhuanlan.zhihu.com/p/541678195
- 下列代码的时间复杂度是()
A. \(O(n^2)\) B. O(n) C. \(O(2^n)\) D. \(O(nlog_2n)\)
解析
答案:B。【解析】递归关系式为T(n)=T(n−1)+O(1),为什么这里是O(1)不是O(n),因为 * n是单个乘法操作,时间消耗为常数。
展开递归:T(n)=T(n−1)+O(1)=(T(n−2)+O(1))+O(1)=(T(n−3)+O(1))+O(1)+O(1)=...=T(1)+O(n)
因为 T(1) = O(1),最终得:T(n)=O(n)
- 下列递归表达式的复杂度是多少()
\(T\left(n\right)=3T\left(n/4\right)+\Theta\left(n^2\right)\)
A.\(O(n^2)\)
B. \(O(2^n)\)
C. \(O (n)\)
D. \(O(n^2log_2n)\)
解析
答案:A。【解析】
【方法一】递归树法。
展开第一层,我们画出根节点下面的三个子节点。其中,表示根节点这一层分解和合并的代价,也就是递归式中
表示的部分。
这样就得到了一棵完整的递归树。每层数据规模缩小为之前的四分之一,直到叶子结点数据规模为1,因此总层数为 。上图最右侧计算了每层所有结点的总代价,计算方式很简单,就是单个结点的代价乘以该层的结点数量。其中,最后一层单个结点的代价为常数,结点数量为
,总代价我们记做
接下来,我们只需要把所有结点的代价加起来,就可以得到递归式的解。
【方法二】主定理(直接记结论)
递归表达式形如:
,且对于某个常数c<1和所有足够大的n有
,则可以推导出
,则
- 例题:
①
- 对于这个递归式,我们有
,此时
。由于
渐进小于
,所以可以应用于主定理的第一种情况,从而得到解
②
- 对于该式,有
,此时
,恰好与
相等,所以可以应用于主定理的第二种情况,从而得到解
③
- 对于该式,有
,此时
。显然
渐进大于
,应考虑主定理的第三种情况。但需要检查是否满足附加条件: 对于某个常数c<1和所有足够大的n有
。带入a 、b和
,得
当 时,该式恒成立,附加条件满足,可以应用主定理的第三种情况,从而得到解
④
- 对于该式,有
,此时
。显然,
渐进大于n ,应考虑主定理的第三种情况。将其带入附加条件,得
当时,该式恒成立。但附加条件要求 c<1 ,因此该式不能使用主方法的第三种情况。也就是说,并非所有形如
的递归式都可以应用主方法求解,情况二和情况三之间是存在空隙的。这种情况我们就只能采用递归树的方法求解了,同学们可以试一下,求出来的结果为