【题目】
有一棵二叉树,其中所有节点的值都不一样,找到含有节点最多 的搜索二叉子树,并返回这棵子树的头节点.
给定二叉树的头结点root,请返回所求的头结点,若出现多个节点最多的子树,返回头结点权值最大的。
【分析】
最大二叉搜索子树,我们只需要使用三个变量保存每个结点为根的子树的min,max,以及它对应的最大二叉搜索子树的结点数目。然后判断是否更新即可。
注意两点:(左半部分最大值用lmax表示,右半部分最小值用rmin表示,t表示当前根节点)
- 如果lmax < t->val < rmin,那么以该结点为根的子树更新为最大二叉搜索子树,最大二叉搜索子树的数目等于左数目+1(自己)+右数目。
- 如不满足1,那就找出左右数目最大的返回即可,继续寻找,并判断是否更新。
【代码】
class MaxSubtree {
public:
TreeNode* getMax(TreeNode* root) {
assert(root != nullptr);
vector<int> res(3, 0);
return get_max_detail(root, res);
}
private:
TreeNode* get_max_detail(TreeNode* t, vector<int>& res){
if(t == nullptr){ //res[0] means min, res[1] means max, res[2] means counter of BST tree node
res[0] = INT_MAX;
res[1] = INT_MIN;
res[2] = 0;
return nullptr;
}
int lmin = 0, lmax = 0, lcnt = 0;
TreeNode* lnode = get_max_detail(t->left, res);
lmin = res[0];
lmax = res[1];
lcnt = res[2];
TreeNode* rnode = get_max_detail(t->right, res);
//don't do like (lnode==null && rnode==null) || (lmax<t->val && rmax>t->val)
//because the lnode or rnoe maybe not the child of the "t".
if((lnode == t->left && rnode == t->right)
&& (lmax < t->val && res[0] > t->val)){ //update
res[0] = std::min(lmin, t->val);
res[1] = std::max(res[1], t->val);
res[2] = lcnt + res[2] + 1;
return t;
}
if(lcnt > res[2]){
//res[0] = lmin; //this line deleted is also ok
//res[1] = lmax; //this line deleted is also ok
res[2] = lcnt;
return lnode;
}
else
return rnode;
}
};
这道题难点在叶子结点的情况,刚开始我处理方式是如图注释中那种情况,没有考虑到如果最大二叉搜索子树不是连续的,即最大二叉搜索子树在某个结点1断开,可能当时最大的二叉搜索子树是结点1的左孩子拥有的子树X(不包括结点1),继续向根部回溯后,出现另外一个右分支中的最大二叉搜索子树Y,它的根的父亲不是结点1,此时如果子树X的最大值 < t->val < 子树Y的最小值,
这样新合成一个包括断点,以及中间可能多个不连续的点的新最大二叉搜索子树,这是错误的!
所以,需要用(lnode==t->left && rnode==t->right && ...)作为判断条件。
值得注意的是,最后有两句话是可以去掉的。因为出现那种情况,等于出现了断层。以后只需要比较它们的数目,不关心它们的min和max了。