在网上找到这个算法,我无法弄清楚如何进行数学运算来发现它的复杂性。我明白最坏的情况是2 ^ n
// A simple recursive function to check whether C is an interleaving of A and B
bool isInterleaved(char *A, char *B, char *C)
{
// Base Case: If all strings are empty
if (!(*A || *B || *C))
return true;
// If C is empty and any of the two strings is not empty
if (*C == '\0')
return false;
// If any of the above mentioned two possibilities is true,
// then return true, otherwise false
return ( (*C == *A) && isInterleaved(A+1, B, C+1))
|| ((*C == *B) && isInterleaved(A, B+1, C+1));
}
答案 0 :(得分:1)
看看你是否可以通过将return
分成更多行来减少问题,
// A simple recursive function to check whether C is an interleaving of A and B
bool isInterleaved(char *A, char *B, char *C)
{
// Base Case: If all strings are empty
if (!(*A || *B || *C))
return true;
// If C is empty and any of the two strings is not empty
if (*C == '\0')
return false;
// If any of the above mentioned two possibilities is true,
// then return true, otherwise false
if ((*C == *A) && isInterleaved(A+1, B, C+1))
return true;
return (*C == *B) && isInterleaved(A, B+1, C+1);
}
"分解" B
生成两种方法
bool isInterleavedA(char *A, char *C)
{
// Base Case: If all strings are empty
if (!(*A || *C))
return true;
// If C is empty and any of the two strings is not empty
if (*C == '\0')
return false;
// If any of the above mentioned two possibilities is true,
// then return true, otherwise false
return (*C == *A) && isInterleavedA(A+1, C+1);
}
bool isInterleavedB(char *A, char *B, char *C)
{
bool result = isInterleavedA(A, C);
if (!(*B) && result)
return true;
return (*C == *B) && isInterleavedB(A, B+1, C+1);
}
现在,我们可以看到isInterleavedA
为O(n)
,而BigOh isInterleavedB
将与isInterleaved
相同,后者将是...... N + MN
?
答案 1 :(得分:1)
将复杂性视为n
中字符数C
的函数。我们称之为f(n)
。
第一个if
块只是进行简单的检查,所以我们暂时可以忽略它们(常数复杂)。
算法的核心当然是这些行:
((*C == *A) && isInterleaved(A+1, B, C+1))
|| ((*C == *B) && isInterleaved(A, B+1, C+1));
检查(*C == ...)
再次是恒定的时间复杂度。现在,isInterleaved(..., ..., C+1)
正在调用算法,其中C
缩短为1:因此复杂度为f(n-1)
。
然后我们可以将它们整合在一起:
f(n) =
k1 +
(k2 + f(n-1)) +
(k3 + f(n-1))
k1
,k2
和k3
是常量。重新排序条款,我们得到:
f(n) = 2 * f(n-1) + k
k
在哪里,又是一些常数。现在,扩展递归,我们得到:
f(n) = 2 * (2 * ( 2 * (... f(0) + k0) + k1) + k2) + ... + k_n)
= 2 * (2 * (2 * (... 2*(2*(f(0) + k0) + k1) + k2) + ... + k_n)
= 2 * (2 * (2 * (... 2*(2^2*(f(0) + k0) + 2*k1) + k2) + ... + k_n)
= 2 * (2 * (2 * (... 2*(2^3*(f(0) + k0) + 2^2*k1 + 2*k2) + ... + k_n)
f(n) = 2^n * (f(0) + k0) + 2^(n-1) * k1 + 2^(n-2) * k2 + ...
将所有内容除以2^n
,我们得到:
f(n) / 2^n = (f(0) + k0) + k1 / 2 + k2 / 4 + ... + k_n / 2^n
所有这些术语都是有界的:无论你总和多少个词,它都是2^{-n}
之和的属性,它将接近2而不会达到它。现在,由于所有k
常量都只是简单的检查,因此它们也是有界的。因此,我们知道存在一些常数K
,k0 < K, k1 < K, ..., k_n < K
。您的f(n)/2^n
随后变为:
f(n) / 2^n < f(0) + K * (1 + 1/2 + 1/4 + ... + 1/2^n)
现在,前两个检查确保f(0)
也是常量,因此您已经证明该函数的复杂度除以2 ^ n确实是有界的,这足以说{{1} }。
你可以浏览其中的大多数&#39;存在一个常数,以便...&#39 ;;要做的主要观察是(使用&#39; handwavily equivalent-ish&#39; symbol f(n) is O(2^n)
):
~
从假设f(n) ~ f(n-1) + f(n-1)
f(n) ~ 2 * f(n-1)
f(n) ~ O(2^n)
的长度是计算复杂性唯一重要的参数开始,我也有点作弊,但是你如何能够严格地证明复杂性对于C
的不同长度来说是等价的而A
留给读者作为练习!
答案 2 :(得分:0)
考虑以下情况。
A = "ab"
B = "aa"
C = "aa"
现在递归将按如下方式执行,
fn(ab, aa, aa)
=> fn(b, aa, a) + fn(ab, a, a)
=> false + fn(b, a, null) + fn(b, null, a) + fn(ab, null, null)
函数调用次数为6。
现在,如果您在第一个中为所有这些添加单个a,例如
A = "aab"
B = "aaa"
C = "aaa"
你会看到这个时间函数调用次数是14。
再添加一个。那么它将是30 ..
然后62然后......
你可以看到它只是2^n - 2
。或者是这样。
所以这里的实际复杂性是2^n
而不是n ^ 2.
这是因为你没有在这里使用记忆。