问题1:Unique-binary-search-trees
题目描述
Given n, how many structurally unique BST's (binary search trees) that store values 1...n?
For example,
Given n = 3, there are a total of 5 unique BST's.
1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 / / \ \ 2 1 2 3
思路:对于选定结点的元素,左边的元素构成左子树,右边的元素构成右子树,左子树和右子树构成种树的乘积就是总的个数。
考虑根节点,设对于任意根节点k,有f(k)种树的可能。
比k小的k-1个元素构成k的左子树。则左子树有f(k-1)种情况。
比k大的n-k个元素构成k的右子树。则右子树有f(n-k)种情况。
易知,左右子树相互独立,所以f(k)=f(k-1)*f(n-k)。
综上,对于n,结果为k取1,2,3,...,n时,所有f(k)的和。
代码思路:
根据上述思路可以用简单的递归方法快速解决。
现在考虑动态规划求解算法,用数组记录每个f(i)的值,记f(0)=1,f(1)=1。
根据公式:f(k)=f(k-1)*f(n-k),访问数组中的元素。
循环求和,结果更新到数组中。
//unique-binary-search-trees
int numTrees(int n)
{
if(n <= 1)
{
return 1;
}
int* dp = new int[n+1];
dp[0] = 1;
dp[1] = 1;
for(int i=2; i<=n; ++i) //i相当于子树。
{
dp[i] = 0;
for(int j=1; j<=i; ++j) //j表示顶点
{
dp[i] += dp[j-1]*dp[i-j];
}
}
return dp[n];
}
问题2:Unique-binary-search-trees-ii
题目描述
Given n, generate all structurally unique BST's (binary search trees) that store values 1...n.
For example,
Given n = 3, your program should return all 5 unique BST's shown below.
1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 / / \ \ 2 1 2 3
confused what"{1,#,2,3}"means? > read more on how binary tree is serialized on OJ.
思路:选定1-n一个数字i作为根节点,0到i-1是左子树,i+1-n是右子树。 所以需要求出左子树和右子树的所有二叉搜索树的结构,(递归思想)。具体实现见下面代码
vector<TreeNode *> generateTrees(int n)
{
return Create(1,n);
}
vector<TreeNode *> Create(int left, int right)
{
vector<TreeNode *> res;
if(left > right)
{
res.push_back(NULL);
return res;
}
for(int i=left; i<=right; ++i)
{
vector<TreeNode *> leftTree = Create(left,i-1); //左子树所有结构
vector<TreeNode *> rightTree = Create(i+1, right); //右子树所有结构
//根结点所有结构为左子树和右子树的组合
for(int j=0; j<leftTree.size(); ++j)
{
for(int k=0; k<rightTree.size(); ++k)
{
TreeNode* root = new TreeNode(i);
root->left = leftTree[j];
root->right = rightTree[k];
res.push_back(root);
}
}
}
return res;
}
总结:第道题相当于是第一道题的扩展,这两道题共同的思想,递归思想,先求子问题的解,再求整体解。即先求出左子树、右子树的解,然后求整体解。 对于树的问题,首先要想到分解,即左子树和右子树。对于搜索树,要想到左子树的结点均小于根节点,右子树的结点均大于根结点,并且中序遍历是有序的。