二叉树题目练习一(Java)

目录

一、检查两棵树是否相同

二、是否是另一棵树的子树

三、翻转二叉树

四、判断一棵树是否是平衡二叉树

五、判断两棵树是否互为镜像

六、判断一棵树是否是对称二叉树


一、检查两棵树是否相同

题目:相同的树  100.相同的树

     给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例:

 

 思路:

     两棵树相同的条件:根结点一样,左右子树相同(递归问题)。

     考虑有空树的情况:

  • p == null && q != null  : 不是相同的树
  • p != null && q == null  : 不是相同的树
  • p == null && q == null  : 是相同的树(都是空树)

 代码:

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        //两棵树都为空树的情况
        if (p == null && q == null) {
            return true;
        }
        //其中有一棵空树的情况
        //用 || 是因为如果是两棵树都为空树,在上一个 if 中已经判断出来了,不会走到这里
        if (p == null || q == null) {
            return false;
        }

        //代码执行到这里说明两棵树都不为空
        return (p.val == q.val) && (isSameTree(p.left,q.left)) && (isSameTree(p.right,q.right));
        //分开写:(等价于上面一句)
//        if (p.val != q.val) {
//            return false;
//        }
//        if (!isSameTree(p.left,q.left)) {
//            return false;
//        }
//        if (!isSameTree(p.right,q.right)) {
//            return false;
//        } else {
//            return true;
//        }

    }
}

二、是否是另一棵树的子树

题目:另一棵树的子树  572.另一棵树的子树

     给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

     二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

示例:

思路: 

     要判断一棵树是否是另一棵树的子树,则需要分成两个子问题:查找结点和判断是否是相同的树:
     1.查找结点,若树中没有目标子树的根结点,则返回 false,如果有则继续判断。
     2.判断是否是相同的树:根结点一样,左右子树也相同(递归)。
     注意:因为可能会有多个和目标值相同的结点,所以要把所有和目标值相同的结点都找出来,依次判断。在这些结点中:存在相同左右子树的:返回true;都不相同:返回 false;
     因为需要找出所有和目标值相同的元素,所以使用链表将其全部存储起来。

代码:

class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        List<TreeNode> ans = new ArrayList<>();
        contains(root,subRoot,ans);
        //得到所有跟目标值相同的结点,依次判断
        for (TreeNode r : ans) {
            if (isSameTree(r,subRoot)) {
                return true;
            }
        }
        //循环结束,没有相同的
        return false;

    }
    //查找结点
    public void contains(TreeNode p, TreeNode q, List<TreeNode> ans) {
        if (p == null) {
            return ;
        }
        //查看根结点是否和目标结点相同
        if (p.val == q.val) {
            ans.add(p);
        }
        //继续查找其左右子树中是否有目标结点
        contains(p.left,q,ans);
        contains(p.right,q,ans);
    }

    //判断是否是相同的树
    public boolean isSameTree(TreeNode p,TreeNode q) {
        if (p == null && q == null) {
            return true;
        }
        if (p == null || q == null) {
            return false;
        }
        //说明两个树都不为空树
        return (p.val == q.val) && isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
    }
}

三、翻转二叉树

题目:翻转二叉树    226.翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例:

思路: 翻转二叉树:根结点不变,左子树变成右子树,右子树变成左子树

思路1:新定义一个结点,将根结点复制过去,再将原树的左子树变成新结点的右子树,将原树的右子树变成新结点的左子树。注意:当树为空树时,返回 null。

代码:

    public TreeNode invertTree(TreeNode root) {
        if (root == null) {
            return null;
        }
        TreeNode ans = new TreeNode(root.val);
        ans.left = invertTree(root.right);
        ans.right = invertTree(root.left);

        return ans;
    }
}

思路2:在原来的树上直接进行操作(前序遍历,先交换元素,再遍历左右子树)。根结点不变,变换左右子树(注意到底是左子树还是右子树)。

代码:

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null) {
            return null;
        }
        //翻转左右子树
        TreeNode tmp = root.right;
        root.right = root.left;
        root.left = tmp;

        //翻转左右子树
        invertTree(root.left);
        invertTree(root.right);

        return root;
    }
}

四、判断一棵树是否是平衡二叉树

题目:平衡二叉树    110.平衡二叉树 

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

示例:

 思路:

     遍历思路:遍历每一个结点,获取两个子树的高度,比较高度差。一旦存在 |高度差| > 1,说明不是平衡二叉树。若全部 |高度差| <= 1,则说明是平衡二叉树。

     子问题思路:

  • 根:|左子树高度 - 右子树高度| <= 1
  • 左子树:是一棵平衡二叉树
  • 右子树:是一棵平衡二叉树

代码:这里使用子问题思路 

class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) {
            return true;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        //子问题思路
        if ((leftHeight - rightHeight) > 1 || (rightHeight - leftHeight) > 1) {
            return false;
        }
        return isBalanced(root.left) && isBalanced(root.right);
        
    }
    public int getHeight(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        return Integer.max(leftHeight,rightHeight) + 1;
    }
}

五、判断两棵树是否互为镜像

思路:

     假设两棵树都不是空树,则互为镜像的条件:(规模较小的子树相同问题(递归))

  • p 的根的值 == q 的根的值
  • p 的左子树 和 q 的左子树互为镜像;
  • p 的右子树 和 q 的右子树互为镜像。

     涉及到空树的情况:

  • p == null && q == null     ->   true
  • p == null && q != null      ->   false
  • p != null && q == null      ->   false

 代码:

    public boolean isMirror(TreeNode p, TreeNode q) {
        //先处理涉及到空树的情况
        if (p == null && q == null) {
            return true;
        }
        if (p == null || q == null) {
            return false;
        }
        //代码执行到这里说明两棵树均不为空,子问题思路
        //注意互为镜像,p 的左子树应该对应 q 的右子树,p 的右子树对应 q 的左子树
        return p.val == q.val
                && isMirror(p.left,q.right)
                && isMirror(p.right,q.left);
    }

六、判断一棵树是否是对称二叉树

题目:对称二叉树      101.对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

示例: 

 思路:利用是否互为镜像,即左右子树是否互为镜像。

      将判断是否对称(复杂问题)-> 判断是否互为镜像(简单问题)。即将复杂问题化成小问题(子问题)

     小问题:

  • 可能是另一种问题—— 子步骤
  • 也可能是规模较小的相同问题—— 递归

代码: 

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        //不为空树
        return isMirror(root.left,root.right);
    }

    //是否互为镜像
    public boolean isMirror(TreeNode p,TreeNode q) {
        if (p == null && q == null) {
            return true;
        }
        if (p == null || q == null) {
            return false;
        }

        return p.val == q.val
                && isMirror(p.left,q.right)
                && isMirror(p.right,q.left);
    }
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值