1. 程式人生 > 實用技巧 >leetcode:不同的二叉搜尋樹

leetcode:不同的二叉搜尋樹

給定一個整數n,生成所有由 1 ...n為節點所組成的二叉搜尋樹。

輸入:3
輸出:
[
[1,null,3,2],
[3,2,null,1],
[3,1,null,null,2],
[2,1,3],
[1,null,2,null,3]
]

  1. 二叉搜尋樹:它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別為二叉排序樹。
  2. 求二叉搜尋樹的個數是卡特蘭問題,

因為空樹也是一種二叉搜尋樹,我們將n = 0時賦值為1。

n = 1 時的情況可以看做是其左子樹個數乘以右子樹的個數,左右子樹都是空樹,所以1乘1還是1。

n = 2 時,由於1和2都可以為根,分別算出來,再把它們加起來即可。

我們用dp[i]表示當有i個數字能組成的BST的個數,則 n = 2時的計算表示式可以表示如下:

dp[2] = dp[0] * dp[1]   (1為根的情況,因為是二叉搜尋樹,則左子樹一定不存在,右子樹可以有一個數字)

    + dp[1] * dp[0]   (2為根的情況,因為是二叉搜尋樹,則左子樹可以有一個數字,右子樹一定不存在)

n = 3 時,由於1、2和3都可以為根,根據上面的推導,我們知道二叉搜尋樹排列個數會由以n個不同數為根時各種情況下剩下的n-1個數所可能的子樹排列情況累加而成,在計算這種排列情況時要藉助二叉搜尋樹有序的性質,由此可以寫出 n = 3時的計算表示式:

dp[3] = dp[0] * dp[2]   (1為根的情況,則左子樹一定不存在,右子樹可以有兩個數字)

    + dp[1] * dp[1]   (2為根的情況,則左右子樹都可以各有一個數字)

    + dp[2] * dp[0]   (3為根的情況,則左子樹可以有兩個數字,右子樹一定不存在)

  3. 針對本題,根據二叉搜尋樹的性質我們可以知道左子樹的節點值的集合為 [1 \ldots i-1][1…i−1],右子樹的節點值的集合為 [i+1 \ldots n][i+1…n]。而左子樹和右子 樹的生成相較於原問題是一個序列長度縮小的子問題,因此可以用用遞迴的方法來解決這道題目。

class Solution:
    def generateTrees(self, n: int) -> List[TreeNode]:
        '''#返回二叉搜尋樹個數:卡特蘭數
        dp=[0]*(n+1)  #dp[i]表示當有i個數字能組成的 BST的個數
        dp[0],dp[1]=1,1
        for i in range(2,n+1):
            for k in range(i):
                dp[i]+=dp[k]*dp[i-k-1]
        return dp[n]'''
        def generateTrees(start,end):
            if start>end:
                return [None]  #這裡很重要,遞迴的出口必須寫成[None],返回空節點
            Tree=[]
            for i in range(start,end+1):
                leftTree=generateTrees(start,i-1)
                rightTree=generateTrees(i+1,end)
                for l in leftTree:
                    for r in rightTree:
                        curTree=TreeNode(i)
                        curTree.left=l
                        curTree.right=r
                        #print(l)
                        Tree.append(curTree)   
            return Tree
        return generateTrees(1,n) if n else []   #如果輸入為空則返回[]