leetcode96-不同構的二叉搜尋樹的個數/卡特蘭數
阿新 • • 發佈:2018-12-03
給出一個 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,有多少個不同的出棧序列?待補充。。。