1. 程式人生 > >每天一道LeetCode-----生成由[1 : n]這n個數組成的所有二叉搜尋樹

每天一道LeetCode-----生成由[1 : n]這n個數組成的所有二叉搜尋樹

Unique Binary Search Trees

這裡寫圖片描述

給定數值n,計算有多少種不同的二叉搜尋樹能夠儲存1,2,...,n這n個數

二叉搜尋樹滿足的條件

  • 當前根節點的值大於左子樹節點的值
  • 當前根節點的值小於右子樹節點的值
  • 左右子樹同樣是二叉搜尋樹

根據上述規則可以看出,根節點值不同,形成的二叉搜尋樹就不同,那麼[1:n]範圍內的n個數就有n個不同的選擇

假設選取i作為根節點值,根據二叉搜尋樹的規則,[1:i1]這i-1個數在其左子樹上,[i+1:n]這n-i個數在其右子樹上

對於由[1:i1]形成的左子樹,又可以採用上述方法進行分解

對於由[i+1:n]形成的右子樹,同樣可以採用上述方法進行分解

由於每個分解的範圍都是連續遞增的,所以無需考慮具體數值。另G(n)表示由連續的n個數形成的二叉搜尋樹的個數

那麼G(n)為所求解,假設以i作為分界點,那麼左子樹為G(i-1),右子樹為G(n-i)

因為i可以取從1到n的任意一個數,所以G(n)=ni=1(G(i1)G(ni))

需要對G(0)和G(1)特殊處理,令其為1,即G(0)=G(1)=1

程式碼如下

class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n + 1, 0);
        dp[0] = dp[1] = 1
; for(int i = 2; i <= n; ++i) { for(int j = 1; j <= i; ++j) { //G(i) += G(j - 1) * G(n - j) dp[i] += dp[j - 1] * dp[i - j]; } } return dp[n]; } };

Unique Binary Search Trees II

不再是計算有多少個不同的二叉搜尋樹,而是將所有不同的二叉搜尋樹構造出來:smile:

還是以上面的題為基礎,假設選擇i作為分界點,那麼左子樹由[1:i1]範圍的值組成,右子樹由[i+1:n]範圍內的值組成

通過[1:i1]這i-1個數可以構成多個不同的二叉搜尋樹,假設是leftTree1leftTree2,....,leftTreeL

通過[i+1:n]這n-i個數可以構成多個不同的二叉搜尋樹,假設是rightTree1,rightTree2,...,rightTreeR

那麼可知以i作為根節點的二叉搜尋樹共有LR個,另這些樹依次組成即可求出這LR個樹

程式碼如下

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<TreeNode*> generateTrees(int n) {
        return generateTrees(1, n);    
    }
private:
    //返回由[start : end]組成的所有樹
    vector<TreeNode*> generateTrees(int start, int end)
    {
        vector<TreeNode*> trees;
        //如果只有一個元素,直接構建返回
        if(start == end)
        {
            trees.emplace_back(new TreeNode(start));
            return trees;
        }
        //範圍內無元素,直接返回
        if(start > end)
        {
            return trees;
        }

        for(int i = start; i <= end; ++i)
        {
            //以i作為分界點獲取左右兩部分的子樹集合
            vector<TreeNode*> leftTrees = generateTrees(start, i - 1);
            vector<TreeNode*> rightTrees = generateTrees(i + 1, end);
            //如果是空,手動增加nullptr節點,否則for迴圈進不去!!!
            if(leftTrees.empty())   leftTrees.emplace_back(nullptr);
            if(rightTrees.empty())  rightTrees.emplace_back(nullptr);
            //依次組合所有可能
            for(auto leftTree : leftTrees)
            {
                for(auto rightTree : rightTrees)
                {
                    //構建以i為值的根節點,新增左右子樹,新增到結果中
                    TreeNode *root = new TreeNode(i);
                    root->left = leftTree;
                    root->right = rightTree;
                    trees.emplace_back(root);
                }
            }
        }
        //繼續返回上一層
        return trees;
    }
};

這兩道題比較重要,真的很重要:cry:

對於如何構建二叉搜尋樹,只需要將其拆分成左右兩部分,再組合集合。計算所有BST的數量利用的是動態規劃,公式推導一遍應該可以理解(Letex公式真的好用:smile:)