卡特兰数(Catalan Number)及其应用

定义

卡特兰数是一个常出现在各种计数问题中的数列, 其满足的递推方程如下:
$$C(n) = \sum_{k=0}^{n-1} C(k) \times C(n-1-k), n \gt 0$$
令初始值$C(0) = 1$,其前几项为:1, 1, 2, 5, 14, 42...
其通项公式有多种写法,如用生成函数法可以直接由以上递推方程求出,这里暂且不表,仅取一种简洁且易于计算的形式:
$$C(n) = \frac{1}{n+1}\binom{2n}{n}$$

应用

卡特兰数可以应用于许多有趣的组合数学问题及CS中的计数问题,列举其中部分:

  1. n个数共有多少种不同的出栈序列? -- C(n).
  2. n对括号共有多少种合法配对形式?e.g., n = 2,()(), (()) -- C(n).
  3. 给n+1个相乘的数加括号,e.g., n=2, ((ab)c), (a(bc)). 共有多少种方法? --- C(n).
  4. 有n个节点的二叉树(问二叉搜索树(BST)也一样), 有多少种不同构成形式?-- C(n).
  5. 有n+1个叶子结点的满二叉树,共有多少种? -- C(n).
  6. 将凸n+2边形以不相交的对角线分割为n个三角形,共有多少种方法? -- C(n).
  7. n个-1和n个1构成的序列中,满足任意前缀和都大于0的有多少种? -- C(n). 这个问题可以将-1看成入栈,1看成出栈,前缀和大于0的序列等价于出栈序列。

由此衍生出许多问题,通常都可以写出定义中的递推方程。如一道笔试题:
在图书馆一共6个人在排队,3个还《面试宝典》一书,3个在借《面试宝典》一书,图书馆此时没有了面试宝典了,求他们排队的总数?
-- 类似例题7,由C(3)=5,但注意组合的问题都认为物品是相同的,这里还要考虑3个不同的人的排列,因此总数: 5 * 3!* 3! = 180.

计算

现在上code来计算第n个组合数$C(n)$. 分别从递推公式和通项公式出发有两种方法:

动态规划

根据递推公式很容易写出动规, 在忘记通项公式的时候可以使用, 大多数情况不会超时。

int catalan(int n) {
    vector dp(n+1, 0);
    for (int i = 1; i <= n; ++i)
        for (int j = 0; j <= i - 1; ++j)
            dp[i] += dp[j] * dp[i-1-j];
    return dp[n];
}
  • 时间复杂度:$O(n^2)$
  • 空间复杂度:$O(n)$

计算组合数

如果记得通项公式,那么直接计算组合数更快,利用我在另一篇文章的提到的方法compute_binomial 可以在O(n)时间完成.

int catalan(int n) {
    return compute_binomial(2*n, n) / (n+1);
}
  • 时间复杂度:$O(n)$
  • 空间复杂度:$O(1)$

你可能感兴趣的:(算法,组合数学)