卡特兰数是一个常出如今各类计数问题中的数列, 其知足的递推方程以下:
$$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中的计数问题,列举其中部分:segmentfault
由此衍生出许多问题,一般均可以写出定义中的递推方程。如一道笔试题:
在图书馆一共6我的在排队,3个还《面试宝典》一书,3个在借《面试宝典》一书,图书馆此时没有了面试宝典了,求他们排队的总数?
-- 相似例题7,由C(3)=5,但注意组合的问题都认为物品是相同的,这里还要考虑3个不一样的人的排列,所以总数: 5 * 3!* 3! = 180.函数
如今上code来计算第n个组合数$C(n)$. 分别从递推公式和通项公式出发有两种方法:code
根据递推公式很容易写出动规, 在忘记通项公式的时候能够使用, 大多数状况不会超时。get
int catalan(int n) { vector<int> 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]; }
若是记得通项公式,那么直接计算组合数更快,利用我在另外一篇文章的提到的方法compute_binomial 能够在O(n)时间完成.数学
int catalan(int n) { return compute_binomial(2*n, n) / (n+1); }