大O表示法 - 递归

时间:2015-12-03 12:01:27

标签: algorithm complexity-theory

在网上找到这个算法,我无法弄清楚如何进行数学运算来发现它的复杂性。我明白最坏的情况是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));
}

3 个答案:

答案 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);
}

现在,我们可以看到isInterleavedAO(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))

k1k2k3是常量。重新排序条款,我们得到: 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常量都只是简单的检查,因此它们也是有界的。因此,我们知道存在一些常数Kk0 < 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.

这是因为你没有在这里使用记忆。