6

以下函数生成加泰罗尼亚数字中的第 n 个数字。该函数的确切时间复杂度函数是多少,或者我自己如何找到它?

int catalan(int n)
{
    if (n==0 || n==1)
        return 1;

    int sum = 0;
    for(int i=1;i<n;i++)
        sum += catalan(i)*catalan(n-i);
    return sum;
}

注意:我知道这是计算加泰罗尼亚数字的最糟糕的方法。

4

3 回答 3

13

为了评估复杂性,让我们关注执行的递归调用的数量,让C(n).

调用n意味着精确2(n-1)的递归调用,每个调用都增加了自己的成本,2(C(1)+C(2)+...C(n-1)).

调用n+1意味着精确2n的递归调用,每个调用都增加了自己的成本,2(C(1)+C(2)+...C(n-1)+C(n)).

差,C(n+1)-C(n) = 2+2C(n)可以写成C(n) = 2+3C(n-1)

C(1) = 0
C(2) = 2+2C(1) = 2+3C(0) = 2
C(3) = 4+2(C(1)+C(2)) = 2+3C(2) = 8
C(3) = 6+2(C(1)+C(2)+C(3)) = 2+3C(3) = 26
C(4) = 8+2(C(1)+C(2)+C(3)+C(4)) = 2+3C(4) = 80
...
C(n) = 2n-2+2(C(1)+C(2)+...C(n-1)) = 2+3C(n-1)

为了轻松解决这种重复,请注意

C(n)+1 = 3(C(n-1)+1) = 9(C(n-2)+1) = ...3^(n-2)(C(2)+1) = 3^(n-1)

因此,对于n>1确切的公式是

C(n) = 3^(n-1)-1

对(常数时间)的调用次数Catalan(1)也是C(n),加法或乘法的次数分别是C(n)/2

通过注意到循环中的所有项(除了中间项)都计算了两次,很容易将复杂性从 降低O(3^n)O(2^n)—— 但这仍然不能使其成为可接受的实现:)

于 2014-12-09T08:21:26.023 回答
9

认为

  1. 除 for-loop 以外的任何步骤都是 k;
  2. for循环中的求和和倍数是c和
  3. 加泰罗尼亚语(r) 是 T(r)

在 catalan(n) 的 for 循环中,catalan(i) 执行 n-1 次,其中 i 的值从 1 到 n-1,catalan(ni) 执行 n-1 次,其中 ni 的值从 n-1 到 1 . 简而言之,catalan(i) 和 catalan(ni) 等于所有 catalan(x) 的两倍,其中 x 的值从 1 到 n-1。

T(n) = 2(T(1) + T(2) + T(3) + ... + T(n-2) + T(n-1)) + k + (n-1)c
Similarly, 
T(n-1) = 2(T(1) + T(2) + T(3) + ... + T(n-2)) + k + (n-2)c

Reorder T(n) as 2(T(1) + T(2) + T(3) + ... + T(n-2)) + 2T(n-1) + k + (n-2)c + c
T(n) = 2(T(1) + T(2) + T(3) + ... + T(n-2)) + k + (n-2)c + 2T(n-1) + c
T(n) = T(n-1) + 2T(n-1) + c
T(n) = 3T(n-1) + c
T(n) = (3^2)T(n-2) + 3c + c
T(n) = (3^3)T(n-3) + (3^2)c + 3c + c
and so on...
T(n) = (3^(n-1))T(n-(n-1)) + c(3^0 + 3^1 + 3^2 + ... + 3^(n-2))
T(n) = (3^(n-1))T(1) + ((3^(n-1)-1)/2)c

所以,时间复杂度是O(3 ^ N)

于 2014-12-09T06:44:21.380 回答
2

我的过程与@hk6279 的过程非常相似,但我相信更容易理解,因为我从代码本身开始。我开始在代码中定义递归关系,然后替换它。

我还从@hk6279 的方法中删除了所有 + k + c 变量,因为它给方程增加了噪音,最后所有这些变量都将被排除。

递归关系

T(n) => 1             -> n = 1
        T(i) * T(n-i) -> n > 1; for i in 1..n-1

当 n > 1 时可视化

T(n) = [T(1) + T(2) + T(3) + .... + T(n-2) + T(n-1)] + [T(n-1) + T(n-2) + .... + T(3) + T(2) + T(1)]
T(n) = [T(1) + T(2) + T(3) + .... + T(n-2) + T(n-1)] + [T(1) + T(2) + T(3) + .... + T(n-2) + T(n-1)]
T(n) = 2 * [T(1) + T(2) + T(3) + .... + T(n-2) + T(n-1)]

什么是 T(n-1) ?

T(n-1) = 2 * [T(1) + T(2) + T(3) + .... + T(n-2)]

替换为 T(n-1)

T(n) = 2 * [T(1) + T(2) + T(3) + .... + T(n-2) + T(n-1)]
T(n) = 2 * [T(1) + T(2) + T(3) + .... + T(n-2)] + 2 * [T(n-1)]
T(n) = T(n-1) + 2 * [T(n-1)]
T(n) = 3 * T(n-1)

什么是 T(n-2) ?

T(n-2) = 2 * [T(1) + T(2) + T(3) + .... + T(n-3)]

替换为 T(n-2)

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

替换为 T(nk)

T(n) = 3^k * T(n-k)

if n - k = 1 => k = n + 1

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

时间复杂度

O(3^n)
于 2021-07-29T10:25:00.430 回答