96. Unique Binary Search Trees and 95. Unique Binary Search Trees II

 

可以看到第二道题要更复杂些,其实第二道题求出来的时候,第一个遍迎刃而解无非就是统计一下个数对吧。

其实在不要树的具体结构只要个数的情况下即第一道题有更简便,更好的解题方式即其可以看做是动态规划问题

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第一个问题:

我们假设dp[i]表示给定一个数其多少种BST数结构

对于给定n即1,2,3,4,,,,n

我们依次取其为树的根节点比如取4为根节点时,那么其左树就是:

1,2,3

右树就是:

5,6,,,,n

抽象的话就是当选取i为根节点时,左树就是:

1,2,3,,,i-1,

右树就是

i+1,2,3,4,5,,,n

那么左树1,2,3,,,i-1有多少种情况呢?毫无以为是dp[i-1]

右数呢?

注意i+1,2,3,4,5,,,n是n-i种情况即dp[n-i]

这里就稍微解释一下为什么是n-i,其实当给定一组连续数字其所能构成的BST树的数量只和这一组连续数字的个数有关,和数字大小是无关的具体来说就是[3,4,5,6]所能构成的BST树数量和[100,101,102,103]所能构成的BST树数量是相同的

所以对于i为根节点时一共有:

dp[i-1]*dp[n-i]

种情况

所以当给定n,我们算其所能构成BST树的所有数量时应该是:

for(int i=1;i<=n;i++){
    result+=(dp[i-1]+dp[n-i]);
}

这个for的作用就是遍历让所有的i都当一次根节点

现在假设n=3,我们可能要用到dp[1],dp[2]

所以我们必须外面再加一个for循环,其作用就是我们先算当n=1时能构成的BST树数量,再算n=2时能构成的BST树数量,一次次递归上去

代码如下:

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

    }
};

总结一下:

dp[n]记录的就是n所对应的BST树数量的结果

里面的for循环左右就是让当前j下这一组数分别作为根节点进而计算j对应下的BST树总数

外面的for作用就是

真真的动态规划部分

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第二道题虽然代码复杂,但思路简单,直接看代码更容易理解,这里直接给一下吧:

/**
 * 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 *> Helper(int begin, int end)
    {
        vector<TreeNode *> ret;
        if(begin > end)
            ret.push_back(NULL);
        else if(begin == end)
        {
            TreeNode* node = new TreeNode(begin);
            ret.push_back(node);
        }
        else
        {
            for(int i = begin; i <= end; i ++)
            {//root
                vector<TreeNode *> left = Helper(begin, i-1);
                vector<TreeNode *> right = Helper(i+1, end);
                for(int l = 0; l < left.size(); l ++)
                {
                    for(int r = 0; r < right.size(); r ++)
                    {
                        //new tree
                        TreeNode* root = new TreeNode(i);
                        root->left = left[l];
                        root->right = right[r];
                        ret.push_back(root);
                    }
                }
            }
        }
        return ret;
    }
    vector<TreeNode*> generateTrees(int n) {
        if (n==0){
            return vector<TreeNode*>(0);
        }
        return Helper(1,n);
        
    }
};

这里比较难理解的应该是两个for的过程吧,

其实也很简单,就是数学上面的简单组合,将左右两个树不断两两组合,ret中记录着所有两两组合的情况。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值