举例:
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
递归/动态规划的思路,在于思考中间状态,递归尤其是要考虑得到的新值与返回值。
对于本题而言,判断平衡二叉树,必须要求所有子树均为平衡二叉树。
在中间状态,需要得到三个值:左子树的高度、右子树的高度、左子树&右子树是否平衡?
需要返回两个值:我本身的高度、我是否平衡?
结构体如下:
public static class ReturnType{
//这就是一个结构体 也就是一个静态类
public boolean isBalanced;
public int height;
//我们需要的是 我本身是否平衡 与 我的高度是多少?
//ReturnType就是返回的类型
public ReturnType(boolean isB,int hei)
{
isBalanced = isB;
height = hei;
//构造函数构造一下。
}
}
//建造一个返回类型的构造体
在上文的构造体的基础上,我们为之添加递归的条件。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {//递归
public boolean isBalanced(TreeNode root) {
return process(root).isBalanced;
//主函数,返回的便是ReturnType类中的isBalanced属性
}
public static class ReturnType{
public boolean isBalanced;
public int height;
public ReturnType(boolean isB,int hei)
{
isBalanced = isB;
height = hei;
}
}
//建造一个返回类型的构造体
public static ReturnType process(TreeNode root){
//注意 这里返回的是ReturnType类型的 也就是说返回两个值
if(root==null) return new ReturnType(true,0);//末尾条件
//递归通常考虑边界条件
//本题的边界条件便是 root==null 也就是到了空节点
//我们直接返回true(必然是平衡的)以及0(空树)
//实际上孩子结点也可以 那样return的就是true和1了
ReturnType leftdata = process(root.left);
ReturnType rightdata = process(root.right);
//左右孩子的返回值 ReturnType类型的两个对象
//接下来我也得返回两个信息
int height = Math.max(leftdata.height,rightdata.height)+1;
//左右孩子更高的那个+1
boolean isBalanced = leftdata.isBalanced && rightdata.isBalanced && Math.abs(leftdata.height - rightdata.height)<2 ;
return new ReturnType(isBalanced,height);
//将ReturnTYpe拆分反悔回去
}
}
再来个新例子:
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
同样地,我们也需要一个ReturnType类来保存返回值
思考一下,我们如何判断一个树是二叉搜索?那么必须要求:左子树中的最大值小于当前结点,右子树的最小值大于当前结点,左&右子树必须均为二叉搜索树。
这样返回值也就很明确了:该树中的最大值,该树中的最小值,该树是否为搜索树?
public static class Returndata //注意这里是建立返回值结构体
{
public boolean isBST;
public int min;
public int max;
public Returndata(boolean isBST,int min,int max)
{
this.isBST = isBST;
this.min = min;
this.max = max;
}
}
然后思考边界条件:叶子结点。
叶子结点的最大最小都是自己,然后必然是二叉搜索树。
接下来,判断的流程是,每次根结点和递归而来的返回值进行比较,校正最大值和最小值之后。然后判断是否符合二叉搜索树,然后返回ReturnType即可。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
//非递归解法
//我们需要一个结构体(类) 包括该结点为头的二叉树是不是搜索二叉树 以及该点的值!
public boolean isValidBST(TreeNode root) {
return process(root).isBST;
}
public static class Returndata //注意这里是建立返回值结构体
{
public boolean isBST;
public int min;
public int max;
public Returndata(boolean isBST,int min,int max)
{
this.isBST = isBST;
this.min = min;
this.max = max;
}
}
public static Returndata process(TreeNode root)
{
if(root==null) return null;
Returndata left = process(root.left);
Returndata right = process(root.right);
boolean isbst = true;
int min = root.val;
int max = root.val;
if(right!=null){
min = Math.min(right.min,min);
max = Math.max(right.max,max);
}
if(left!=null){
min = Math.min(left.min,min);
max = Math.max(left.max,max);
}
if(right!=null)
{
isbst = right.isBST && right.min>root.val && isbst;
}
if(left!=null)
{
isbst = left.isBST && left.max<root.val && isbst;
}
return new Returndata(isbst,min,max);
}
}