可以看到第二道题要更复杂些,其实第二道题求出来的时候,第一个遍迎刃而解无非就是统计一下个数对吧。
其实在不要树的具体结构只要个数的情况下即第一道题有更简便,更好的解题方式即其可以看做是动态规划问题
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第一个问题:
我们假设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中记录着所有两两组合的情况。