卡特蘭數是一個常出如今各類計數問題中的數列, 其知足的遞推方程以下:
$$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); }