编辑:我想出了如何正确计算时间复杂度,但仍然无法计算出存储复杂度。
编辑:把所有东西都弄清楚了。
我尝试解决复杂性问题,但失败了。
答案应该是:时间复杂度-n(m + n),存储复杂度-m + n。
请帮助我了解我在哪里错了,并提出一种更好地理解/解决这类问题的方法。
功能如下:
void f(int n, int m){
if (n <= 1) {
int *arr=malloc(m*sizeof(int));
for (int i=0; i<m; i++) arr[i] = 0;
free(arr);
return;
}
f(n-1, m+1);
f(n%2, m+1);
}
从我看到的“ free(arr)”中释放了malloc分配的内存,这使得malloc在时间复杂度方面不受欢迎。 编辑:有人向我解释说,即使我们使用“免费”,仍然会考虑malloc(明智地使用空间cpmlexity)。
我看到第一个函数调用使函数本身调用了n次,并且在发生这种情况时m增加了1-n次,因此,第一次函数调用的时间复杂度为n(m + 1),存储复杂度n-,因为有n个函数递归调用。编辑:最终找到答案。
第二个函数调用调用函数log(n)次,m增加log(n)次,这使该调用的时间复杂度为:log(n)(m + 1)。 存储复杂度:log(n)。
所以总时间复杂度为n(m + 1),总存储复杂度为n。
答案 0 :(得分:0)
这实际上是一个棘手的问题!
第二个函数调用f(n%2, m+1)
仅调用递归f,因为它计算n到2的提醒,该提醒可以为1或0!在这两种情况下,都将返回f函数,而无需进行任何进一步的递归调用。
因此它不是log n。
函数f在f(n-1, m+1)
中被调用了n次,而紧接着在f(n%2, m+1)
中被调用了,它将再次被调用一次。如果仅考虑n个因子,则为O(2n)。
现在考虑m因子,我们将注意到if内的循环重复m次,并且在每个递归调用中m均增加1(并且在从递归调用返回时实际上减小)! (m + n ... m + 1)的和为O(mn + n(n + 1)/ 2)。简化之后。
因此,考虑这两个因素,时间复杂度为O(2n + mn + n(n + 1)/ 2),实际上简化后等于 O(nm + n ^ 2) )。
关于存储复杂度:第一个调用(m + 1)的m会增加n,这将持续n次,但第二个调用不会继续,因此存储复杂性将为 O(n + m)。
答案 1 :(得分:0)
void f(int n, int m){
if (n <= 1) {
int *arr=malloc(m*sizeof(int));
for (int i=0; i<m; i++) arr[i] = 0;
free(arr);
return;
}
f(n-1, m+1);
f(n%2, m+1);
}
我们重构它:
void f1(int m) {
int *arr = malloc(m*sizeof(int));
for (int i = 0; i < m; i++) {
arr[i] = 0;
}
free(arr);
}
void f(int n, int m){
if (n <= 1) {
f1(m);
return;
}
f(n-1, m+1);
f(n%2, m+1);
}
对于f1来说,它非常简单-空间复杂度为sizeof(int) * m
-我们需要分配很多空间-时间复杂度仅为m
-我们正在遍历所有m
元素在数组arr
中。
n%2
只能是1
或0
,因此我们可以用f(n%2, m+1);
代替f1(m+1)
。
void f(int n, int m){
if (n <= 1) {
f1(m); // (1)
return;
}
f(n-1, m+1); // (2)
f1(m + 1); // (3)
}
现在。如果为n > 1
,则我们调用f(n-1, ...
直到n <= 1
。对于每个n > 1
,我们以相反的时间顺序调用f1(m + 1)
(因为它在递归调用之后)。当我们到达n <= 1
时,将f1(m)
次调用m = m(initial) + n(initial) - 1
。
等等,例如n=5
的示例,然后:
f(5, m)
的初始调用,因此n = 5 f(4, m+1)
//(2)f(3, m+2)
//(2)f(2, m+3)
//(2)f(1, m+4)
//(2)f1(m+4)
并返回//(1)f1(m+4)
//(3)f1(m+3)
//(3)f1(m+2)
//(3)f1(m+1)
//(3)我们可以看到f1(m+4)
被两次调用,并且我们从f1(m + i)
到i=1
的相反顺序调用i=4
。
我们可以“展开”功能:
void f(int n, int m){
f1(m + n - 1);
for (int i = n - 1; i > 0; --i) {
f1(m + i);
}
}
由于m
和n
都接近无穷大,因此+1
或-1
毫无意义。
空间复杂度是f1(max(m + i, m + n - 1))
的空间复杂度,因为f1
每次都会释放内存。因此,(m + n - 1) * sizeof(int)
是(m + n) * sizeof(int)
,也就是m + n
。
时间复杂度取决于我们调用f1
函数的次数。我们看到我们称呼为:
f1(m + n - 1)
f1(m + n - 1)
f1(m + n - 2)
...
f1(m + 2)
f1(m + 1)
所以时间复杂度是
(m + n - 1) + ((m + n - 1) + (m + n - 2) + ... + (m + 1))
(m + n - 1) + (n - 1) * m + ((n - 1) + (n - 2) + ... 1)
(m + n - 1) + (n - 1) * m + ((n - 1) * (n - 1 + 1) / 2)
(m + n - 1) + (n - 1) * m + ((n - 1) * (n - 1 + 1) / 2)
// the `*2`, `/2`, `+1` and `-1` mean nothing close to infinity
m + n + n * m + n * n
m + n + m * n + n * n
m * (n + 1) + n * (n + 1)
(m + n) * (n + 1)
(m + n) * n