演算法學習筆記 卡特蘭數

2022-01-10 04:31:30 字數 4572 閱讀 8196

卡特蘭數(catalan numbers, oeis a000108 (opens new window))是組合數學中乙個常出現在各種計數問題中的數列。

數列的前幾項為:1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862,...

卡特蘭數是乙個非常神奇的序列,它與許多看似千差萬別的問題都有著緊密的關聯。這些問題包括:

這是一道最經典的入門級卡特蘭數題目,如果能把這題看懂,相信後面的題目也能迎刃而解。

題目描述

n 個元素進棧序列為:1,2,3,4,...,n,則有多少種出棧序列

思路

我們將進棧表示為 +1,出棧表示為 -1,則 1 3 2 的出棧序列可以表示為:+1 -1 +1 +1 -1 -1

根據棧本身的特點,每次出棧的時候,必定之前有元素入棧,即對於每個 -1 前面都有乙個 +1 相對應。因此,出棧序列的所有字首和必然大於等於 0,並且 +1 的數量等於 -1 的數量。

接下來讓我們觀察一下 n = 3 的一種出棧序列:+1 -1 -1 +1 -1 +1。序列前三項和小於 0,顯然這是個非法的序列。

如果將第乙個字首和小於 0 的字首,即前三項元素都進行取反,就會得到:-1 +1 +1 +1 -1 +1。此時有3 + 1個 +1 以及3 - 1個 -1。

因為這個小於 0 的字首和必然是 -1,且 -1 比 +1 多乙個,取反後,-1 比 +1 少乙個,則 +1 變為 n + 1 個,且 -1 變為 n - 1 個。進一步推廣,對於 n 元素的每種非法出棧序列,都會對應乙個含有n + 1個 +1 以及n - 1個 -1 的序列。

如何證明這兩種序列是一一對應的?

假設非法序列為 a,對應的序列為 b。每個 a 只有乙個"第乙個字首和小於 0 的字首",所以每個 a 只能產生乙個 b。而每個 b 想要還原到 a,就需要找到"第乙個字首和大於 0 的字首",顯然 b 也只能產生乙個 a。

每個 b 都有n + 1個 +1 以及n - 1個 -1,因此 b 的數量為 \(c_^\) ,相當於在長度為 2n 的序列中找到n + 1個位置存放 +1。相應的,非法序列的數量也就等於 \(c_^\)

出棧序列的總數量共有 \(c_^\),因此,合法的出棧序列的數量為 \(c_^n - c_^ = \frac^n}\)。

此時我們就得到了卡特蘭數的通項 \(\frac^n}\),至於具體如何計算結果將會在後面進行介紹。

題目描述

n 對括號,則有多少種 「括號匹配」 的括號序列

思路

左括號看成 +1,右括號看成 -1,那麼就和上題的進出棧一樣,共有

題目描述

n + 1 個葉子節點能夠構成多少種形狀不同的(國際)滿二叉樹

(國際)滿二叉樹定義:如果一棵二叉樹的結點要麼是葉子結點,要麼它有兩個子結點,這樣的樹就是滿二叉樹。

思路使用深度優先搜尋這個滿二叉樹,向左擴充套件時標記為 +1,向右擴充套件時標記為 -1。

由於每個非葉子節點都有兩個左右子節點,所有它必然會先向左擴充套件,再向右擴充套件。總體下來,左右擴充套件將會形成匹配,即變成進出棧的題型。n + 1 個葉子結點會有 2n 次擴充套件,構成 \(\frac^n}\) 種形狀不同的滿二叉樹。

題目描述

電影票一張 50 coin,且售票廳沒有 coin。m 個人各自持有 50 coin,n 個人各自持有 100 coin。

則有多少種排隊方式,可以讓每個人都買到電影票。

思路

持有 50 coin 的人每次購票時不需要找零,並且可以幫助後面持有 100 coin 的人找零;而對於持有 100 coin 的人每次購票時需要找零,但 100 coin 對後面的找零沒有任何作用。

因此,相當於每個持有 100 coin 的人都需要和乙個持有 50 coin 的人進行匹配。我們將持有 50 coin 的標記為 +1,持有 100 coin 的標記為 -1,此時又回到了進出棧問題。

不同的是,m 並一定等於 n,且排隊序列是一種排列,需要考慮先後順序,例如各自持有 50 coin 的甲和乙的前後關係會造成兩種不同的排隊序列。所以,將會有 \((c_^m - c_^) * m! * n!\)

第二項為什麼是 \(c_^\) ,其實很簡單,我們每次把第乙個字首小於0 的字首取反後,會造成 +1 多了乙個而 -1 少了乙個。這裡 +1 有 m 個,-1 有 n 個,取反後 +1 變成m + 1個,-1 變成n - 1個,總和不變。

奇偶性卡特蘭數\(c_n\)是奇數,當且僅當\(n=2^k-1\)。

證明:\[c_n=\frac=\frac

\]顯然\((2n-1)!!\)中不含\(2\),所以要判斷\(c_n\)的奇偶性,也就要判斷\((n+1)!\)含有多少個\(2\)。

這時,我們有:

\[t=\lfloor\frac\rfloor+\lfloor\frac\rfloor+\cdots+\lfloor\frac\rfloor

也即\(t\leq n\)。其中\(k=\argmax_t(2^t\leq n+1)\)。

下面我們要說明\(n=2^k-1\)是等號成立的充要條件。

充分性是顯然的,將\(n=2^k-1\)代入上式,可得:

\[t=2^+2^+\cdots+1=2^k-1=n

\]下面說明必要性。設\(n=2^k+x,0\leq x<2^k-1\),則\(n+1<2^\),也即\(k=\argmax_t(2^t\leq n+1)\)依然成立。

此時,原式左邊變為:

\[l.h.s=2^k-1+\lfloor\frac\rfloor+\lfloor\frac\rfloor+\cdots+\lfloor\frac\rfloor

\]從而:

\[l.h.s<2^k-1+x+1=2^k+x=n

\]這樣,我們就說明了原命題的充要性。進而可知,\(c_n\)為奇數,當且僅當\(n=2^k-1\)。

質數所有卡特蘭數中只有兩個質數,\(c_2=2\)以及\(c_3=5\)。

最後我們總結一下卡特蘭數的通項

\[c_n = \frac^n}

\]卡特蘭數滿足以下遞推式:

\[c_1 = 1,c_n = c_\frac

\]因此,我們可以通過遞推來得到第 n 個卡特蘭數。

**

//cpp

#includeusing namespace std;

int main()

}

需要注意的是,由於卡特蘭數增長速度較快,當 n 等於 17 時,卡特蘭數將會超過int最大值,造成溢位(python 除外)。

那如果 +1 的數量不等於 -1 的數量呢,如前面提到的電影購票問題。此時 \(c_n = c_^m -c_^\) ,不是卡特蘭數的通項,也就不能夠繼續使用原有的遞推性質。

那就直接推唄。

一般而言,為了降低難度,題目會要求我們計算排列數量,所以 \(a_n = c_n * m! * n! = (m + n)! * \frac\)

基本上所有的卡特蘭數問題經過一定的轉換都可以還原成進出棧問題。因此,只要我們能夠學會進出棧問題的解法,無論問題再怎麼變化,本質還是不變的。

卡特蘭數問題中都會存在一種匹配關係,如進出棧匹配,括號匹配等,一旦計數問題中存在這種關係,那我們就需要去考慮這是否是卡特蘭數問題。此外,我們還可以記住序列前四項:1, 1, 2, 5,這些將有利於我們聯想到卡特蘭數。

同時,近年某巴巴,某訊的筆試題中也有出現過這類題目,無非將背景換成買燒餅,借書排隊等,相信這些都難不倒讀者。

8 個高矮不同的人需要排成兩隊,每隊 4 個人。其中,每排都是從低到高排列,且第二排的第 i 個人比第一排中第 i 個人高,則有多少種排隊方式。

學習筆記 卡特蘭數

鑑於noip初賽考到了卡特蘭數.整理一下。湊合著看。一 介紹 卡特蘭數是一種經典的組合數,經常出現在各種計算中,其前幾項為 1,2,5,14,42,132,429,1430,4862,16796,58786,208012,742900,2674440,9694845,35357670,1296447...

牛客網演算法學習筆記 卡特蘭數相關

說實話,卡特蘭數我自己基本沒什麼深刻的理解,只能做一些相關的簡單的題目而已。所以這裡只記錄題目和 n個數進出棧的順序有多少種?假設棧的容量無限大。給定乙個整數n,請返回所求的進出棧順序個數。保證結果在int範圍內。測試樣例 1返回 1 2n個人排隊買票,n個人拿5塊錢,n個人拿10塊錢,票價是5塊錢...

卡特蘭數,高精度卡特蘭數

簡單介紹 卡特蘭數是組合數學中常常出現的乙個數列。個人認為不管是遞推公式還是代表的含義都比斐波那契數列難理解一些。遞推公式 應用 1.cn表示長度2n的dyck word的個數。dyck word是乙個有n個x和n個y組成的字串。且全部的字首字串皆滿足x的個數大於等於y的個數。下面為長度為6的dyc...