引言:
最近在刷题过程中,二叉树的题还是相对来说比较简单的。那是因为二叉树的各类题型都是相关的,都是有迹可循。在二叉树的各种遍历是最简单的,而我在刷题过程中却碰到了一些二叉树的生成,看到题意后感觉无从下手,所以我就写下这篇文章来加深自己对这类题的印象。
题目1:所有可能的满二叉树
题目链接
**题目描述:**满二叉树是一类二叉树,其中每个结点恰好有 0 或 2 个子结点。返回包含 N 个结点的所有可能满二叉树的列表。 答案的每个元素都是一个可能树的根结点。答案中每个树的每个结点都必须有 node.val=0。你可以按任何顺序返回树的最终列表。
输入输出:
题解:
首先看到二叉树的题,就要有一种意识,那就是考虑递归(除非层次遍历相关的题)。然后再考虑二叉树的性质。满二叉树的节点数必须是奇数,否则无法构成。并且它的左右子树也要是满二叉树。
左子树的节点数可以是1,3,5,…,N-2;右子树的相应的节点数就是N-2,…,5,3,1.所以递归的生成左右子树,然后让根节点连接左子树的各种情况,和右子树相应的各种情况即可。保存每种情况,然后返回即可。
代码:
/**
* 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*> help(int N)
{
vector<TreeNode*> ve;
if(N%2==0) return ve;
if(N==1){
TreeNode *t=new TreeNode(0);
ve.push_back(t);
return ve;
}
for(int i=1;i<N;i+=2)//i+=2保证左右子树0的个数为奇数
{
vector<TreeNode*> left=help(i); //建立有i个的左子树,也是满二叉树
vector<TreeNode*> right=help(N-1-i); //建立有N-1-i个的右子树,也是满二叉树
for(TreeNode* l:left)
for(TreeNode* r:right){
TreeNode* t=new TreeNode(0); //以t为根,左子树为left的各种可能,右子树是right的各种可能
t->left=l;
t->right=r;
ve.push_back(t);
}
}
return ve;
}
vector<TreeNode*> allPossibleFBT(int N) {
return help(N);
}
};
题目2:不同的二叉搜索树
题目链接
题目描述:
给定一个整数 n,生成所有由 1 … n 为节点所组成的二叉搜索树。
输入输出:
题解:
这一题和上一题相似,差不多就可以说一模一样了,可以使用相同的模板。这不过二叉树的性质不同了.但是只要找出二叉树性质的特点就不难写出此题。上一题的性质上面已经说清楚了,而这一题二叉树的性质就是①根节点的值大于左子树各结点的值,小于右子树各节点的值,②还有就是左右子树也必须是二叉搜索树。而此题的各节点的值是1,2,3,…,n.只要保证先确定一点为根节点的值,然后小于该点的各数建立左子树,大于该点的各数建立右子树,天然的保证了此题二叉搜索树的性质。所以只需遍历1到n,让该处的值作为根节点的值,左子树取遍各种左子树集合中的各值,右子树取遍各种右子树集合中的各值,然后一组合即可。最后把组合的情况保存起来并返回即可。
代码:
/**
* 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*> help(int L,int R)
{
vector<TreeNode*> ve;
if(L>R){
ve.push_back(NULL);
return ve;
}
for(int i=L;i<=R;i++)
{
vector<TreeNode*> left_nodes=help(L,i-1); //从L到i-1生成一个二叉搜索树
vector<TreeNode*> right_nodes=help(i+1,R); //从i+1到R生成一个二叉搜索树
for(TreeNode* left_node :left_nodes)
for(TreeNode* right_node:right_nodes)
{
TreeNode *t=new TreeNode(i);//然后让i为根左子树是L到i-1的二叉搜索树右子树是 i+1到R的二叉搜索树
t->left=left_node;
t->right=right_node;
ve.push_back(t);
}
}
return ve;
}
vector<TreeNode*> generateTrees(int n) {
if(n==0) return vector<TreeNode*> {};
return help(1,n);
}
};
结尾:
二叉树的题相对来说是比较容易的,只要每一类题(创建、遍历等)都有深刻的理解,那么做二叉树的题应该就没什么问题了。