1. 程式人生 > >卡特蘭數相關

卡特蘭數相關

卡特蘭數 - lz_666888 - lz_666888的部落格

(7)圓桌握手問題: 圓桌周圍有 2n個人,他們兩兩握手,但沒有交叉的方案數。

(8)本文的“n對括號正確匹配組成的字串數”問題。

雖然同屬於卡特蘭數問題,但是用同樣的方法解釋似乎行不通(看百度百科上的解釋:關於出棧的問題。還是比較容易理解的,但是我卻不能通過它理解本題)

最後發現是《程式設計之美2》這本書上的原題。其解釋如下:

分析

    “卡特蘭數”除了可以使用公式計算,也可以採用“分級排列法”來求解。以 n對括弧的合法匹配為例,對於一個序列 (()而言,有兩個左括弧,和一個右括弧,可以看成“抵消了一對括弧,還剩下一個左括弧等待抵消”,那麼說明還可以在末尾增加一個右括弧,或者一個左括弧,沒有左括弧剩餘的時候,不能新增右括弧。

    由此,問題可以理解為,總共 2n個括弧,求 1~2n級的情況,第 i 級儲存所有剩餘 i 個左括號的排列方案數。 1~8級的計算過程如下表:

這裡,我搞了很久才折騰明白,行1-8表示級數–括弧個數,列0-8表示不完整匹配左括號個數。紅色為博主解釋,其他為原文

卡特蘭數 - lz_666888 - lz_666888的部落格

比如:1級: 只有一個,只能是左括號(。右括號不能先出現啊。

                      不完整左括號個數為  1個。                      (

             2級:由1級的左括號(,如果給它右括號,則完整匹配;此時不完整匹配左括號個數為0,因此在0這一列下為1;

                                                      如果給再給它左括號,則不完整匹配左括號個數為2,只有一種情況: ((         個數為1

                                                      不完整匹配左括號個數為1這種情況不存在!!!因此不填。

             3級:一定是不完整的,所以不完整匹配左括號個數為0 的下方  空缺;

                       由2級可知,原來有完整匹配 1個”()”,   現在又增加了1個括弧,那麼只能又出現了一個不完整匹配左括號

                                            原來有不完整匹配左括號2個“((“,現在如果增加一個右括號,則不完整匹配左括號個數為1的情況+1

                                                                                                              如果增加一個左括號,則不完整匹配左括號個數為3的情況+1

       現在明白為什麼下一級的個數為上一級相鄰兩邊相加。比如3級 1列(0列起始)下=2級0列+2級2列。

依次類推:

        4級:原來3級中有2個不完整1次括弧,那麼4級中就有   完整匹配    2次。

                 4級中不完整2次括弧=3級的不完整1次+3級的不完整3次。

                4級的不完整4次括弧 只能是”((((“全左括號,所以每行最後一個數字為1,表示全左括號。

over

    計算過程解釋如下: 1級:只能放 1個“(”; 2級:可以在一級末尾增加一個“)”或者一個“ (”

以後每級計算時,如果遇到剩餘 n>0個“(”的方案,可以在末尾增加一個“ (”或者“ )”進入下一級;遇到剩餘 n=0個“(”的方案,可以在末尾增加一個“ (”進入下一級。

奇數級只能包含剩餘奇數個“(”的排列方案

偶數級只能包含剩餘偶數個“(”的排列方案

從表中可以看出,灰色部分可以不用計算。

解法

關鍵程式碼為:

double Catalan(int n) { if (n == 0) return 1; for (int i = 2; i <= 2 * n; i++) { var m = i <= n ? i : 2 * n + 1 - i; for (int j = (i - 1) & 1; j <= m; j += 2) { if (j > 0) arr[j - 1] += arr[j]; if (j < n) arr[j + 1] += arr[j]; arr[j] = 0; } } return arr[0]; }

其中:

n為 Cn中的 n;

arr = new double[n + 1];//arr[i]代表有 k個括弧的時候,剩餘 “(“個數為 i的排列方案個數 arr[1] = 1;

討論

演算法複雜度為 卡特蘭數 - lz_666888 - lz_666888的部落格 = O(n^2),空間複雜度為 O(n+1)。相對於利用公式計算而言,此方法的優勢在於——沒有乘除法,只有加法。