树的递归问题

递归:

  • 注意当前节点做的事如何利用返回值 – 思考用什么类型的返回值,怎么操作返回值?
    因此,返回值的类型也可以确定了。

  • 注意是否要利用其他private函数,如果用,那么private函数的输入参数和返回值是什么。

  • 要求树的整体的某个值,比如树的直径,树是否是平衡的,应该定义一个全局变量。

  1. 树的深度/高度(数得是边数,不是节点数)
public int maxDepth(TreeNode root){
	if (root == null) return 0;
	int l = maxDepth(roo.left);
	int r = maxDepth(root.right);
	return Math.max(l, r) + 1;
}
  1. 判断平衡树(利用1:树的深度/高度)
private boolean result = true;

public boolean isBalanced(TreeNode root){
	maxDepth(root);
	return result;
}

private int maxDepth(TreeNode root){
	if (root == null) return 0;
	int l = maxDepth(root.left);
	int r = maxDepth(root.right);
	if (Math.abs(l - r) > 1) result = false;
	return Math.max(l, r) + 1;	
}
  1. 树的直径(数得边数,正好利用1:树的深度/高度)
private int max = 0;
public int diameterOfTree(TreeNode root) {
	maxDepth(root);
	return max;
}
private int maxDepth(TreeNode root){
	if (root == null) return 0;
	int l = maxDepth(roo.left);
	int r = maxDepth(root.right);
	max = Math.max(max, l+r);
	return Math.max(l, r) + 1;
}
  1. 翻转树
public TreeNode invertTree(TreeNode root){
	if (root == null) return null;
	TreeNode left = root.left;
	root.left = invertTree(root.right);
	root.right = invertTree(left);
	return root;
}
  1. 合并树
public TreeNode mergeTrees(TreeNode t1, TreeNode t2){
	//停止条件:
	if (t1 == null && t2 == null) return null; 
	if (t1 == null) return t2;
	if (t2 == null) return t1;
	//当前节点操作:
	TreeNode root = new TreeNode(t1.val + t2.val); //新建节点
	//交给递归:
	root.left = mergeTrees(t1.left, t2.left); 
	root.right = mergeTrees(t1.right, t2.right);
	//返回:
	return root;
}
  1. 是否有路径和(路径和定义为从 root 到 leaf 的所有节点的和)== targetSum
public boolean pathSum(TreeNode root, int targetSum) {
	if (root == null) return false;
    if (root.left == null && root.right == null && root.val == sum) return true;
    return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
  1. 路径和(路径不一定以 root 开头,也不一定以 leaf 结尾,但是必须连续)== targetSum 的数量

第一重递归:遍历树的每一个节点。
第二重递归:计算从每一个节点出发一共能有多少条路径。

 //遍历树的每一个节点(以当前节点为root,以root.left为root, 以root.right为root),把返回的ret(路径和=targetSum数)加起来
    public int pathSum(TreeNode root, int sum) {
        if (root == null) return 0;
        int ret = pathSumWithRoot(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
        return ret;
    }
    //返回以每一个节点为root的路径数
    private int pathSumWithRoot(TreeNode root, int sum) {
        if (root == null) return 0;
        int ret = 0;
        if (root.val == sum) ret++;
        ret += pathSumWithRoot(root.left, sum - root.val) + pathSumWithRoot(root.right, sum - root.val);
        return ret;
    }
	
  1. 判断 树t 是否是 另一棵树s 的子树

双层递归函数,递归函数又套了另一个递归函数。外面的递归函数用于遍历每一个节点(输入当前节点root,操作root,root.left, root.right);内层递归函数作用于当前节点,根据题意进行设计,是主要“做事”的函数。

第一重递归:遍历树的每一个节点。
第二重递归:判断以当前节点为root的树是不是t这个子树。

	//遍历树的每一个节点(以当前节点为root,以root.left为root, 以root.right为root),判断树t是否是s的子树
    public boolean isSubtree(TreeNode root, TreeNode t) {
	    if (root == null) return false;
	    return isSubtreeWithRoot(root, t) || isSubtree(root.left, t) || isSubtree(root.right, t);
    }
    //判断以当前节点为root的树是不是t这个子树
    private boolean isSubtreeWithRoot(TreeNode root, TreeNode t) {
	    if (root == null && t == null) return true;
	    if (root == null || t == null) return false;
	    return root.val == t.val && isSubtreeWithRoot(root.left, t.left) && isSubtreeWithRoot(root.right, t.right);
    }
  1. 判断树是否symmetric

判断对称的标准:
左右节点值要相同
左节点的左子和右节点的右子要对称,右节点的左子和左节点的右子要对称。

	//判断root的左右节点是否对称,调用isSymmetric(root.left, root.right)
    public boolean isSymmetric(TreeNode root) {
	    if (root == null) return true;
        return isSymmetric(root.left, root.right);
    }

    //判断对称的递归函数:判断当前节点的左右节点是不是对称的,若要对称,则要满足:节点值相同;左节点的左子和右节点的右子对称 && 左节点的右子和右节点的左子对称
    private boolean isSymmetric(TreeNode left, TreeNode right) {
        if (left == null && right == null) return true;
        if (left == null || right == null) return false;
        return left.val == right.val && isSymmetric(left.left, right.right) && isSymmetric(left.right, right.left);

    }
 
  1. 最小路径(数的是节点数量,从root到leaf的最短距离)

和maxDepth不同,minDepth不能只写Math.min(l, r) + 1。

public int minDepth(TreeNode root) {
        if (root == null) return 0;
        int l = minDepth(root.left);
        int r = minDepth(root.right);
        //若一边有距离,一边没距离,那最短距离就是有距离的那边的距离+1
        if (l == 0 || r == 0) return l + r + 1;
        //若两边都有距离,选近的距离那边,+1
        return Math.min(l, r) + 1;

    }
  1. 左叶子之和

当前节点操作:
如果当前节点的左子是leaf node,那么左子val + 右子树递归;
如果当前节点的左右子都不是leaf node,那么左右子树分别递归,求和。

public int sumOfLeftLeaves(TreeNode root) {
        //别忘了corner case:null
        if (root == null) return 0;
        //如果当前节点的左子是leaf node,那么左子val + 右子树递归
        if (isLeaf(root.left)) return root.left.val + sumOfLeftLeaves(root.right);
        //如果当前节点的左右子都不是leaf node,那么左右子树分别递归,求和
        return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
    }
    //判断当前节点是否是leaf node
    private boolean isLeaf(TreeNode root) {
    	//corner case:null
        if (root == null) return false;
        //要满足左右子都是null才是leaf node
        return root.left == null && root.right == null;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值