当前位置: 首页 > article >正文

二叉树(下)

目录

判断树是否相同

判断树是不是另一棵树的子树

二叉树翻转

判断平衡二叉树

 二叉树层序遍历


这篇主要提供一些关于二叉树例题的讲解,如果对二叉树及其基本操作有疑问的可以转至:

二叉树(上)-CSDN博客
二叉树(中)-CSDN博客

判断树是否相同

力扣链接:100. 相同的树 - 力扣(LeetCode)

题目描述:

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

思路

这里主要从两方面去思考两棵树是否相同:结构和数值。分别是对应下面的图片

这道题的难点在于如何把这个思路进行代码形式的转换。

首先我们可以先判断结构是否相同,

        if(p != null && q == null || p == null && q != null){
            return false;
        }

剩下的两种情况为:两者都为空 或者 两者都不为空,再排除掉两者都为空的情况,

        if(p == null && q == null){
            return true;
        }

接着判断其中的值是否相同,

        if(p.val != q.val){
            return false;
        }

最后存留下来的情况是:值都不为空且值一样,此时就可以继续进行递归来保证两棵树的每一个节点都是一样的。

return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);

完整代码为

//时间复杂度, min(p, q)
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        //1.先判断结构是否相同
        if(p != null && q == null || p == null && q != null){
            return false;
        }
        //2.剩下的两种情况为 空或者相等
        if(p == null && q == null){
            return true;
        }
        //都不为空,判断值是否一样
        if(p.val != q.val){
            return false;
        }
        //都不为空且值一样
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }
}

判断树是不是另一棵树的子树

力扣链接:572. 另一棵树的子树 - 力扣(LeetCode)

情况可以大致分为以下三种:

 思路为:

  1. 当前子树和根节点是否一样?
  2. 判断子树是不是和当前root的左子树一样?
  3. 判断子树是不是和当前root的右子树一样?

这里其实也调用了上面写的 判断树是否相同 的代码,

先用 root 和 subRoot(子树) 进行判断树是否相同,然后用root的左子树和右子树同subroot进行递归比较,分别进行比较和返回。

注意:先是比较两棵树是否为子树关系,然后进行递归。

//时间复杂度
//root共有节点r个,subRoot共有节点s个
//时间复杂度为O(r * s)
class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(root == null){
            return false;
        }
        if(isSameTree(root, subRoot)) return true;
        if(isSubtree(root.left, subRoot)) return true;
        if(isSubtree(root.right , subRoot)) return true;

        return false;
    }

    public boolean isSameTree(TreeNode p, TreeNode q) {
        //1.先判断结构是否相同
        if(p != null && q == null || p == null && q != null){
            return false;
        }
        //2.剩下的两种情况为 空或者相等
        if(p == null && q == null){
            return true;
        }
        //都不为空,判断值是否一样
        if(p.val != q.val){
            return false;
        }
        //都不为空且值一样
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }
    
}

二叉树翻转

力扣链接:226. 翻转二叉树 - 力扣(LeetCode)

 

 主要思路其实和数据的交换位置是一个类型的,像是下面的代码部分

        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;

然后进行递归,同时加上递归条件和特定情况

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null){
            return root;
        }
        //避免叶子节点再进行
        if(root.left == null && root.right == null){
            return null;
        }
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        invertTree(root.left);
        invertTree(root.right);

        return root;
    }
}

判断平衡二叉树

力扣链接:110. 平衡二叉树 - 力扣(LeetCode)

平衡二叉树:如果一棵树是二叉树,那么它的每棵子树都是平衡二叉树。

左右子树高度差 <=1;如果 >=2 则不是平衡二叉树

思路:遍历这棵树的节点,求每个节点的左树和右树的高度,如果发现h >=2,则返回false。

判断整棵树会发现根节点的左子树为平衡二叉树,右子树也是平衡二叉树。

 这里可以先尝试把框架搭建出来:求左子树的高度和右子树的高度,

    public boolean isBalanced(TreeNode root) {
        if(root == null){
            return true;
        }

        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);

        return Math.abs(leftHeight - rightHeight) < 2
        && isBalanced(root.left) && isBalanced(root.right);
    }

因为要求每棵树的左右树高,所以我们需写一个额外的方法来进行。

    public int getHeight(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftTree = getHeight(root.left);
        int rightTree = getHeight(root.right);

        return leftTree > rightTree ? leftTree + 1 : rightTree +1;
    }

完整代码为

//时间复杂度为O(N^2)
class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root == null){
            return true;
        }

        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);

        return Math.abs(leftHeight - rightHeight) < 2
        && isBalanced(root.left) && isBalanced(root.right);

    }

    public int getHeight(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftTree = getHeight(root.left);
        int rightTree = getHeight(root.right);

        return leftTree > rightTree ? leftTree + 1 : rightTree +1;
    }
}

 二叉树层序遍历

力扣链接:102. 二叉树的层序遍历 - 力扣(LeetCode)

第一种方法:队列

思路:主要是依靠队列来实现层序遍历,先把头节点设为cur,询问队列时候为空,再去除头节点,并输出,若左右子树不为则分别放入左右子树 

public void levelOrder(TreeNode root){
    if(root == null){
        return;
    }
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);

    while(!queue.isEmpty()){
        TreeNode cur = queue.poll();
        System.out.print(cur.val + " ");
        if(cur.left != null){
            queue.offer(cur.left);
        }
        if(cur.right != null){
            queue.offer(cur.right);
        }
    }
}

第二种方法:队列 + 二维数组 

也就是力扣链接里的题目,它主要是让我们把每一层的数据放在一起,这里我们可以通过定义一个size变量,来记录每一层数据的个数。

public List<List<Integer>> levelOrder2(TreeNode root) {
    List<List<Integer>> ret = new ArrayList<>();
    if (root == null) {
        return ret;
    }


    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);

    while (!queue.isEmpty()) {
        int size = queue.size();
        List<Integer> list = new ArrayList<>();
        while (size != 0) {
            TreeNode cur = queue.poll();
            list.add(cur.val);
            //System.out.print(cur.val + " ");
            if (cur.left != null) {
                queue.offer(cur.left);
            }
            if (cur.right != null) {
                queue.offer(cur.right);
            }
            size--;
        }
        ret.add(list);
    }
    return ret;
}


http://www.kler.cn/news/311771.html

相关文章:

  • Conda Config修改
  • 深度学习-18-深入理解BERT实战使用预训练的DistilBERT模型
  • 【Vue嵌套数据中,实现动态表头和内容】
  • 不会JS逆向也能高效结合Scrapy与Selenium实现爬虫抓取
  • 前端框架对比和选择?
  • [学习笔记]树链剖分(简易版) 及其LCA
  • Redis实践之缓存:设置缓存过期策略
  • 计算机网络33——文件系统
  • sqli-labs靶场自动化利用工具——第13关
  • RabbitMQ 和 Kafka 的详细对比表格
  • 消息队列:如何确保消息不会丢失?
  • 自然语言处理实战项目全解析
  • 阻止冒泡事件
  • Python中的异步编程:从基础知识到高级应用
  • vi | vim基本使用
  • 视频相关处理
  • 基于Delphi的题库生成系统
  • spark读mongodb
  • HTB-Jerry(tomcat war文件、msfvenom)
  • Unity制作角色溶解变成光点消失
  • GPT提示词分享 —— 深度思考助手
  • 【Vue】VueRouter路由
  • Spring系统学习(一)——初识Spring框架
  • 第五届“马栏山杯”国际音视频算法大赛创新应用赛投票环节正式启动啦!
  • Json和Http专栏
  • linux如何查看当前的目录所在位置
  • GDPU 信息安全 天码行空1 用Wireshark分析典型TCP/IP体系中的协议
  • 【vue】vue3+ts对接科大讯飞大模型3.5智能AI
  • MongoDB的安装和使用
  • React Zustand状态管理库的使用