“嵌套”递归函数的时间和空间复杂性

时间:2018-09-26 14:30:36

标签: recursion time-complexity big-o space-complexity

在先前的cs简介中,有一个问题:将函数f1的空间和时间复杂度计算为n的函数,假设malloc(n)的时间复杂度为O(1),并且空间复杂度为O(n)。

int f1(int n) {
    if(n < 3)
        return 1;

    int* arr = (int*) malloc(sizeof(int) * n);
    f1(f1(n – 3));
    free(arr);

    return n;
} 

官方解决方案是:时间复杂度:O(2 ^(n / 3)),空间复杂度:O(n ^ 2)

我试图解决它,但是直到我在笔记本上看到一条纸条说:我不知道该怎么做:由于该函数返回n,因此我们可以将f(f(n-3))视为f(n-3) )+ f(n-3)或2f(n-3)。在这种情况下,问题变得与此类似:Space complexity of recursive function

我试图用这种方式解决它,我得到了正确的答案。

对于时间复杂度:

  

T(n)= 2T(n-3)+1,T(0)= 1

     
    

T(n-3)= 2T(n-3 * 2)+1

  
     

T(n)= 2 * 2T(n-3 * 2)+ 2 + 1

     
    

T(n-3 * 2)= 2T(n-3 * 3)+1

  
     

T(n)= 2 * 2 * 2T(n-3 * 3)+ 2 * 2 + 2 + 1

     

...

     

T(n)=(2 ^ k)T(n-3 * k)+ 2 ^(k-1)+ ... + 2 ^ 2 + 2 + 1

     
    

n-3 * k = 0

         

k = n / 3

  
     

===> 2 ^(n / 3)+ ... + 2 ^ 2 + 2 + 1 = 2 ^(n / 3)[1+(1/2)+(1/2 ^ 2) + ...] = 2 ^(n / 3)*恒定

因此我得到了O(2 ^(n / 3))

对于空间复杂性:树的深度为n / 3,每次我们进行malloc分配时,我们得到(n / 3)^ 2,因此得到O(n ^ 2)。

我的问题:

  • 为什么我们可以将f1(f1(n – 3))视为f1(n-3)+ f1(n-3)或2f1(n-3)?
  • 如果函数未返回n而是对其进行了更改,例如:返回n / 3而不是返回n,那么我们该如何解决呢?我们将其视为2f1((n-3)/ 3)?
  • 如果我们不能总是将f1(f1(n – 3))视为f1(n-3)+ f1(n-3)或2f1(n-3),那么我们如何绘制递归树并我们如何使用归纳法T(n)编写和解决它?

1 个答案:

答案 0 :(得分:1)

  • 为什么我们可以将f1(f1(n – 3))视为f1(n-3)+ f1(n-3)或2f1(n-3)? < / p>

    因为i)嵌套的f1首先被求值,其返回值用于调用外部的f1;因此这些嵌套调用等效于:

    int result = f1(n - 3);
    f1(result);
    

    ...和ii)f1的返回值只是它的参数(基本情况除外,但渐近无关紧要),因此上述内容还等同于:

    f1(n - 3);
    f1(n - 3); // result = n - 3
    
  • 如果函数未返回n而是对其进行了更改,例如:返回n / 3而不是返回n,那么我们该如何解决呢?我们将其视为2f1((n-3)/ 3)?

    仅外部呼叫受到影响。同样,使用之前的等效表达式:

    f1(n - 3); // = (n - 3) / 3
    f1((n - 3) / 3);
    

    即仅以f1(n - 3) + f1((n - 3) / 3)为例。

  • 如果我们不能总是将f1(f1(n – 3))视为f1(n-3)+ f1(n-3)或2f1(n-3),该怎么办我们绘制了递归树,以及如何使用归纳法T(n)编写并求解它?

    您始终可以如上所述将它们分为两个单独的调用,并再次记住,只有第二个调用受返回结果的影响。如果这与n - 3不同,那么您将需要递归树而不是简单的扩展。取决于具体问题,不用多说。