最近我做了很多卡特蘭數相關的演算法題,閱讀了一些網路上的文章。有的文章過於冗長,太糾結於公式的推導;有的文章又太簡單,只是羅列了相關的題目卻並無解題分析;而且這些文章或多或少都有一些錯誤。所以本文目的是簡明的分析卡特蘭數題目的思路和解法,並且整理的網友的註解。
1. 卡特蘭數
卡特蘭數的具體定義,可以參考wiki 卡塔蘭數。本文只強調它的乙個最重要的遞推公式。
假設c(n)為自然數n對應的卡特蘭數。若c(0)=1,c(1)=1,則有遞推式:
c(n)= c(0)*c(n-1) + c(1)*c(n-2) + ... + c(n-1)c(0) (n>=2)
例如:c(3) = c(0)*c(2) + c(1)*c(1) + c(2)*c(0) = 5
這個遞推式非常重要,下文的每一題都幾乎應用了這個公式。而且也正是這個遞推式讓我們可以用動態規劃或者卡特蘭數的通項公式求解卡特蘭數問題。
2. 演算法題彙總
1)假設乙個二叉樹有n個節點,求所有異構二叉樹數量。
這道題來自 leetcode 第96題 unique binary search trees。
選取任意乙個結點為根,就把二叉樹切成左右兩個子樹,以這個結點為根的可行二叉樹數量就是左右子樹可行二叉樹數量的乘積。遍歷所有的節點並把所有可行結果累加,就得到了總數。寫成表示式如下:
c(n)= c(0)*c(n-1) + c(1)*c(n-2) + ... + c(n-1)c(0) (n>=2)
很明顯這正是卡特蘭數的遞推式。
2)n對左右括號組成乙個字串。求所有滿足以下條件的字串數:要求遇到左括號則入棧,遇到右括號則出棧;處理完後,棧為空。
我們把n對左右括號看作有2n+1個節點的二叉樹。並且使所有節點的左子節點對應左括號,右子節點對應右括號。這樣,除了根節點外的所有節點都與左或者右括號對應。對所有的異構二叉樹做遍歷就得到了所有滿足條件的字串。所以,這道題的本質是求異構二叉樹的數量。
例如,假設我們求3對左右括號有多少滿足條件的字串組合,則可求7個節點的異構二叉樹,並作遍歷即可。如下圖。
3)2n個人排隊買票,其中n個人持50元,n個人持100元。每張票50元,且一人只買一張票。初始時售票處沒有零錢找零。請問這2n個人一共有多少種排隊順序,不至於使售票處找不開錢?
如果把持50元的人看作左括號,持100元的人看作右括號,那麼這道題其實就是問題2)的變體。所以,這道題的本質是求異構二叉樹的數量。
4)n個數連乘,求所有可能的乘法順序。
我們把二叉樹的每個葉節點看作是乘數,那麼遍歷這顆二叉樹就得到了一種可能的乘法順序。所有可能的乘法順序就是求有2n+1個節點的異構二叉樹的總數。所以,這道題的本質是求異構二叉樹的數量。
例如,我們有4個數a b c d連乘,那麼轉換成二叉樹就是:
5)對於乙個n*n的正方形網格,每次我們能向右或者向上移動一格,那麼從左下角到右上角的所有在副對角線右下方的路徑總數為多少。引用wikipedia上的:
如果向右走看作左括號,向上走看作右括號,那麼這道題其實就是問題2)的變體。所以,這道題的本質是求異構二叉樹的數量。
6)凸n+2邊形進行三角形分割數,要求只連線頂點對形成n個三角形。問有多少種不同的分法。
設邊數為n+2,選定任意一條邊作為第乙個三角形的邊,再為它選擇乙個頂點k,1<=k<=n。n邊型被分為了乙個k邊形、乙個三角形和乙個n-k邊形。此時的劃分數為c(k)*c(n-k)。所以對所有的頂點遍歷後,有卡特蘭遞推式:
c(n)= c(0)*c(n-1) + c(1)*c(n-2) + ... + c(n-1)c(0) (n>=2)
7)求n個數的入棧出棧的排列總數。
例如1,2,3的入棧出棧排序有123,132,213,231和321五種。
這道題的本質其實是,如果有n對括號,左括號代表入棧,右括號代表出棧,那麼有多少種出入棧的策略?所以,這道題仍是問題2)的變體。
8)求有2n個數字的集合的不交叉劃分的數目。
這裡解釋一下不交叉劃分。假設將集合劃分為兩個子集和,組成了兩個區間[a,b]和[c,d]。如果這兩個區間不重合,那麼以下四種情況是不交叉的:a
我們注意到每個切割出來的矩形都必需包括一塊標示為*的小正方形,那麼我們此時列舉每個*與#標示的兩角作為矩形,剩下的兩個小階梯就是我們的兩個更小的子問題了,於是我們的c(5) = c(0)*(4) + c(1)*c(3) + c(2)*c(2) + c(1)*c(3) + c(0)*c(4)
10)向乙個兩行n列的方陣中填入數字1到2n,求使每個方格內的數值都比其右邊和下邊的方格內的數值小的排列數。
該題的另一種問法:12個高矮不同的人,排成兩排,每排必須是從矮到高排列,而且第二排比對應的第一排的人高,問排列方式有多少種。
最簡單的排列方法是,把12個人從低到高排列,然後選擇前6個人排在第一排,剩下的人排在第二排。如果用0表示在第一排的人,用1表示在第二排的人,那麼這種方案可以表示為000000111111,也就是:
第一排:0 1 2 3 4 5
第二排:6 7 8 9 10 11
同理,而010101010101對應的方案為:
第一排:0 2 4 6 8 10
第二排:1 3 5 7 9 11
於是問題轉換為:滿足條件的01序列有多少個。如果我們把0看作入棧,1看做出棧,那麼這個問題又可以轉化為,對於乙個序列有多少合法的出棧入棧策略。而這明顯是乙個卡特蘭數問題。
3. 總結:1)以上所有題目實際上都是先得到卡特蘭數的遞推公式,然後求解。
2)以上大部分題目都是問題1)和2)的變體,所以這兩道題很重要,一定要吃透。
卡特蘭數,高精度卡特蘭數
簡單介紹 卡特蘭數是組合數學中常常出現的乙個數列。個人認為不管是遞推公式還是代表的含義都比斐波那契數列難理解一些。遞推公式 應用 1.cn表示長度2n的dyck word的個數。dyck word是乙個有n個x和n個y組成的字串。且全部的字首字串皆滿足x的個數大於等於y的個數。下面為長度為6的dyc...
卡特蘭數和超級卡特蘭數
這篇部落格主要是想講一下超級卡特蘭數 大施洛德數 順帶就想講一下卡特蘭數.卡特蘭數記為 c n c 1 1 forall n geq 2,c n sum c i c 前幾項大概是 1,1,2,5,14,42,132.直接遞推未免效率太低,我們考慮用生成函式優化.顯然有 c x c x 2 x 解得 ...
演算法 卡特蘭Catalan數
catalan數是組合數學中乙個常在各種計數問題中出現的數列。一般項公式為 cn的另乙個表達形式為 一般來說,我們程式設計時使用遞推關係會更方便計算 或即 c n c 1 c n 1 c 2 c n 2 c n 1 c 1 它的前幾項為 1,1,2,5,14,42,132,429,1430,4862...