找到二叉树中的最大搜索二叉树(树形BP)
找到二叉树中的最大搜索二叉树(树形BP)
问题重述:
给定一颗二叉树的头节点root,已知其中所有结点的值都不一样,找到含有节点最多的搜索二叉子树
问题分析:
我们可以每一个结点进行判断,最后得到所有结点中最大的哪一个
解法:
树形BP(递归)
解题:
代码:
public class ReturnType{
// 我们得到的结果需要当前结点的头节点
TreeNode root;
// 我们需要通过当前节点的子树大小来判断最大
int treeSize;
// 需要判断左右子树和当前节点能否满足搜索二叉树,因此需要当前树的最大值和最小值
int max;
int min;
public ReturnType() {}
public ReturnType(TreeNode root,int treeSize,int max,int min){
this.root = root;
this.treeSize = treeSize;
this.max = max;
this.min = min;
}
}
public TreeNode getMaxBST(TreeNode root){
return process(root).root;
}
public ReturnType process(TreeNode root){
// 当前树为null的情况
if(root == null){
// 返回一个对应的ReturnType结点
return new ReturnType(null,0,Integer.MIN_VALUE,Integer.MAX_VALUE);
}
// 获取当前左子树的结果
ReturnType lRoot = process(root.left);
// 获取当前右子树的结果
ReturnType rRoot = process(root.right);
// 通过当前结点和当前结点的左右子树来判断当前的搜索二叉子树
// 首先我们需要判断以当前节点为头节点的子树中的最大节点值和最小结点值
int max = Math.max(root.value,Math.max(lRoot.max,rRoot.max));
int min = Math.min(root.value,Math.min(lRoot.min,rRoot.min));
// 得到以左右节点为最大搜索二叉书的情况
// 最大搜索二叉树的节点数
int treeSize = Math.max(lRoot.treeSize,rRoot.treeSize);
// 最大搜索二叉树的头节点
TreeNode BSTRoot = (lRoot.treeSize > rRoot.TreeSize ? lRoot.root : rRoot.root);
// 当前结点为头节点时是最大搜索二叉树
if(lRoot.treeSize == rRoot.treeSize && root.value > lRoot.max && root.value < rRoot.min){
// 第三种情况,更新头节点和树的大小
treeSize = lRoot.treeSize + rRoot.treeSize + 1;
BSTRoot = root;
}
// 返回当前节点的记录
return new ReturnType(BSTRoot,treeSize,max,min);
}
代码解析:树形动态规划,将一个大的问题,分解成一个一个小问题,我们要计算以一个结点为头节点的最大搜索二叉树,那么,我们把每一个结点的搜索二叉树计算出来,最后从中找到最大的哪一个二叉搜索树就是我们要的结果。而实现这种方式要使用递归的方式
递归函数:首先我们判断为空的情况,然后让当前节点的左右子节点来调用这个函数,这个时候,我们就可以理解为拥有了当前结点和当前结点的左右子树需要的结果。然后我们通过对这当前节点和左右子树进行处理,得到我们想要的结果返回。
以上面的题目为例:我们创建一个新的类型作为递归函数的返回值,新类型中的值都是我们解题需要的,题目要求得到最大二叉搜索树,得到二叉树,我们需要当前的二叉树中的最大二叉树的头节点,因为要进行大小判断,我们需要当前树中最大搜索二叉树的节点数,因为要满足二叉搜索树,所以我们要记录当前二叉树的最大值和最小值,所以我们的新类型是:
public static class ReturnType{
public TreeNode root;
public int treeSize;
public int max;
public int min;
public ReturnType() {}
public ReturnType(TreeNode root,int treeSize,int max,int min){
this.root = root;
this.treeSize = treeSize;
this.max = max;
this.min = min;
}
}
拥有了新类型,我们在递归函数对以节点为头节点的树进行处理,因为已经知道了当前的左右子树中的结果,我们就可以对每一种情况进行处理,然后返回我们需要的结果。有三种可能,一种最大子树在左子树中,一种在右子树中,一种为当前树。分别处理这三种结果就可以
总结:
树形DP:
使用前提:我们要计算的最后结果,可以分解成以每一个节点作为头节点的计算结果,最后结果在这当中
使用步骤:
- 分析以一个结点作为头节点得到结果的所有可能情况
- 根据所有可能情况来创建一个新类型,其中都是我们需要的数据(如果只需要某一个值就不创建新类型)
- 设计递归函数,首先判断为空的情况,然后对当前子树的左右子树分别调用递归函数,得到当前结点的左右子树中的结果
- 通过当前节点和左右子树中的结果对所有可能情况进行处理,处理需要得到以当前结点做为头节点得到的新类型中的数据,然后返回新类型对象