1. 程式人生 > >leetcode96-不同構的二叉搜尋樹的個數/卡特蘭數

leetcode96-不同構的二叉搜尋樹的個數/卡特蘭數

給出一個 n, 用二叉搜尋樹來儲存1 … n,總共有多少種不同構的二叉搜尋樹?

Example:

輸入: 3
輸出: 5
解釋:
給出 n = 3, 總共有5種不同構的二叉搜尋樹:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

開始想的是搜尋,時間複雜度太高。然後查了一下,這是個卡特蘭數的應用場景。


什麼是卡特蘭數?

卡特蘭數是滿足h(n)=h(0)h(n-1)+h(1)h(n-2)+...+h(n-1)h(0)遞推公式的數。

這個問題為什麼是卡特蘭數,因為它滿足上述的遞推公式。下面給出簡單的推導過程。

首先,我們假設n個數1 … n,能夠形成的不同的二叉搜尋樹的個數是f(n)。
考慮,
· 當n為1時,f(1)=?,因為只有一個節點,顯然f(1)=1;

· 當n為2時,有2個節點。
	考慮根節點可以為1,那麼形成的二叉樹為
		1
		 \
		  2
	根節點也可以為2,那麼形成的二叉樹為
		  2
		 /
		1
	>>因此f(2)=2;
	
·當n為3時,有3個節點。
	1.考慮根節點可以為1,那麼形成的二叉樹為
	    1	                                  1
	      \                                     \
	        2            或者                    3
	          \                                 /
	            3	                         2
	2.根節點也可以為2,那麼形成的二叉樹為
		                 2
		                / \
		               1   3
	3.考慮根節點可以為3,那麼形成的二叉樹為
                    3                                   3
                   /                                   /
                  2                                  1
                 /                                     \
              1                                         2
	>>因此f(3)=5;

考慮普遍情況,對於n個節點,根節點為k時:
根節點的左子樹是一顆獨立的樹,同樣右子樹也是一顆獨立的樹。
那麼當根節點k=1時,它的左子樹有0個節點,右子樹有n-1個節點(根節點已經佔了一個節點)。
	·所以對於該左子樹,就是計算0個節點的不同的二叉搜尋樹個數的問題,也就是f(0)。
	·對於右子樹,就是計算n-1個節點的不同的二叉搜尋樹個數的問題,也就是f(n-1)。
	>>由於左右子樹是獨立的問題,所以當根節點k=1時,總個數為左子樹的不同BST個數*右子樹不同BST個數,
	  也就是f(0)*f(n-1)
	
上述只計算了根節點k=1的情況,現在根節點可以取[1,n]之間的任意一個整數。
因此,最後的結果也就是fh(n)=f(0)f(n-1)+f(1)f(n-2)+...+f(n-1)f(0)

這與卡特蘭數的遞推公式相同,因此這是個計算卡特蘭數的問題。

那麼問題來了,上邊我們只分析了這個問題屬於卡特蘭數問題,如何計算卡特蘭數呢?

由於我們已經有了遞推公式,只需寫一個程式來計算即可:

public static int numTrees(int n) {
        if(n<0) return 0;
        int [] f=new int[n+1];
        f[0]=1;
        for(int i=1;i<=n;i++){
            for (int j = 0; j <i ; j++) {
                f[i]+=f[j]*f[i-1-j];
            }
} return f[n]; }

或者也可以通過通項公式來進行計算,不過我個人暫時覺得遞推的方法好些。
下面也給出通項公式(轉載一下吧):
通項公式


還有一些擴充套件的問題也是屬於卡特蘭數的,比如一個棧(無窮大)的進棧序列為1,2,3,…n,有多少個不同的出棧序列?待補充。。。