【问题标题】:Recursion Time Complexity Definition Confusion递归时间复杂度定义混淆
【发布时间】:2019-06-20 03:01:49
【问题描述】:

递归算法的时间复杂度为

Given a recursion algorithm, its time complexity O(T) is typically 
the product of the number of recursion invocations (denoted as R) 
and the time complexity of calculation (denoted as O(s)) 
that incurs along with each recursion 
O(T) = R * O(s)

查看递归函数:

void algo(n){
  if (n == 0) return; // base case just to not have stack overflow
  for(i = 0; i < n; i++);// to do O(n) work 
  algo(n/2);
}

根据上面的定义我可以说,时间复杂度是,R是logn次,O(s)是n。因此结果应该是 n logn,其中与数学归纳法一样,证明结果为 o(n)。

请不要证明归纳法。我在问为什么给定的定义不适用于我的方法。

【问题讨论】:

    标签: recursion time-complexity


    【解决方案1】:

    好问题!这涉及到两种不同的方法来计算递归调用链中完成的工作量。

    您描述的用于计算递归调用中完成的工作量的原始策略 - 将每次调用完成的工作乘以调用次数 - 其中包含一个隐含的假设。也就是说,这假设 每个递归调用都执行相同数量的工作。 如果确实如此,那么您可以将完成的总工作量确定为调用次数和每次调用工作量的乘积.

    但是,如果每次调用完成的工作量随调用参数的变化而变化,则此策略通常不起作用。毕竟,如果没有一个值表示完成了多少工作,我们就不能谈论将调用完成的“工作量”乘以调用次数!

    确定递归调用链完成多少工作的更通用策略是将每个单独的递归调用完成的工作量相加。对于您上面概述的函数,第一次调用完成的工作是 n。第二个调用确实 n/2 工作,因为它所做的工作量在其参数中是线性的。第三次调用完成 n/4 次工作,第四次完成 n/8 次工作,等等。这意味着完成的总工作量为

    n + n/2 + n/4 + n/8 + n/16 + ...

    = n(1 + 1/2 + 1/4 + 1/8 + 1/16 + ...)

    ≤2n,

    这就是更严格的 O(n) 界限的来源。

    请注意,在工作量为每次调用所做的都是一样的。你明白为什么吗?

    或者,如果您可以确定递归调用链完成的工作量的保守上限,则可以将调用次数乘以任何一次调用完成的最大工作量.这永远不会低估总数,但它并不总是给你正确的界限。这就是您列出的示例中发生的情况 - 每个调用最多 n 个工作,并且有 O(log n) 个调用,所以总工作确实是 O(n log n)。这恰好不是一个紧密的界限。

    快速说明 - 我认为将完成的总工作量乘以调用次数的策略称为递归调用链完成的工作量的“定义”是不合适的。如上所述,这更像是一种“确定已完成工作的策略”,而不是正式的定义。如果有的话,我认为正确的正式定义是“每个单独的递归调用完成的工作量的总和”,因为这更准确地说明了将花费多少总时间。

    希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      我认为您正在尝试查找有关主定理的信息,该定理用于证明递归算法的时间复杂度。

      https://en.wikipedia.org/wiki/Master_theorem_(analysis_of_algorithms)

      此外,您通常无法仅通过查看算法运行时间来确定它,尤其是递归算法。这就是为什么您的快速分析不同于归纳证明的原因。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-29
        • 1970-01-01
        • 1970-01-01
        • 2017-11-20
        • 2020-09-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多