每天一道LeetCode-----生成由[1 : n]这n个数组成的所有二叉搜索树

来源:互联网 发布:java stack overflow 编辑:程序博客网 时间:2024/05/21 08:52

Unique Binary Search Trees

原题链接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

原题链接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:)

阅读全文
0 0