在先前的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)。
我的问题:
答案 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
不同,那么您将需要递归树而不是简单的扩展。取决于具体问题,不用多说。