首页 > 编程语言 >Java-数据结构-二叉树-习题(二) (´▽`)ノ

Java-数据结构-二叉树-习题(二) (´▽`)ノ

时间:2024-09-16 14:51:20浏览次数:3  
标签:遍历 Java int 节点 二叉树 return 习题 root 我们

文本目录:

❄️一、习题一(分层遍历):

     ▶ 思路:

      ▶ 代码:

❄️二、习题二(二叉树的最近公共祖先):

      ▶ 思路:

  ▶ 代码:

 ❄️三、习题三(从前序和中序遍历序列中构造二叉树):

       ▶ 思路:

   ▶ 代码:

❄️四、习题四(从中序和后序遍历序列中构造二叉树):

     ▶ 思路:

    ▶ 代码:

❄️五、习题五(根据二叉树创建字符串):

       ▶ 思路:

     ▶ 代码:

❄️六、总结:


❄️一、习题一(分层遍历):

          ☞  题的链接:

                     二叉树的层次遍历  


     ▶ 思路:

     我们的这个题呢和我们在 二叉树的基础那个博客的那个中的层序遍历 是差不多的。我们返回的是 List<List<TreeNode>> 这样的返回类型,我们呢要把每一层的节点放入到 List 当中之后我们在把 List 放入到 List<List<TreeNode>> 当中。

     对于这个题呢,我们要把我们每次入完队的长度计算出来,之后我们出队,并且要把出队的节点的val 放入到 List 当中,直到我们这一层的队列的长度为 0 是就结束,进行下次层的遍历。我们来看看图:

      ▶ 代码:

Ok,我们来看看代码如何编写,是怎样在 层序遍历上进行改变的:

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

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

        while (!queue.isEmpty()) {
            int size = queue.size();
            List<Integer> lsit = new LinkedList<>();

            while (size != 0) {
                TreeNode cur = queue.poll();
                lsit.add(cur.val);

                if (cur.left != null) {
                    queue.offer(cur.left);
                }
                if (cur.right != null) {
                    queue.offer(cur.right);
                }
                size--;
            }
            ret.add(lsit);
        }
        return ret;
    }

❄️二、习题二(二叉树的最近公共祖先):

          ☞  题的链接:

                        二叉树的最近公共祖先       


      ▶ 思路:

       这个题呢还是很简单的,只要理解了就非常简单了。我们先来看看什么是最近的公共祖先,就是我们这两个节点的 p q 的最近的公共节点,我们来看看什么样的:

这种呢就是我们的公共祖先,我们再来看看都有哪些情况对于公共祖先: 

就有这四种情况,当然了我们的 p 和 q 是可以进行交换的。我们来看看它们的条件是什么:

这里要注意的是,我们寻找的是p 和q 的节点,当我们的没有找到的时候呢,我们会返回null

 

 OK,这呢就是这些情况出现的条件了,我们还需要去遍历我们的左子树和右子树找节点。

  ▶ 代码:

我们来看看我们这题的代码的编写:

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {
            return null;
        }

        //第一种情况
        if (root == p || root == q) {
            return root;
        }

        //找节点 p 和 q
        TreeNode leftTree = lowestCommonAncestor(root.left,p,q);
        TreeNode rightTree = lowestCommonAncestor(root.right,p,q);
        //在判断是否为空
        if (leftTree != null && rightTree != null) {
            return root;
        }else if (leftTree != null) {
            return leftTree;
        }else {
            return rightTree;
        }
    }

 ❄️三、习题三(从前序和中序遍历序列中构造二叉树):

          ☞  题的链接:

                        从前序和中序遍历序列中构造二叉树


       ▶ 思路:

     我们知道对于 前序遍历是:根 左 右 。中序遍历是:左  根   右。我们呢就是在前序遍历中寻找根节点,之后用这个根节点在中序中找到这个根节点,这样根节点的左面的数据为左子树,右面的数据为右子树。我们要在中序遍历中要记录中序遍历的开头和结尾,每次的树的创建我们都需要用到,根节点,开头的节点,结尾的节点,这三个节点配合着去创建树,我们这样说呢,不是很直观,我们画个图来分析一下是如何实现的:

这个呢就是我们的这个题的思路, 但是在这里呢我们有一个非常隐蔽的问题,我们来看:

   我们也要记住在设置 左子树 和 右子树 时的 开始位置 和 结束位置 要重新计算,

   在设置左子树的时候 开始位置不变,结束为止为 根节点 - 1

   在设置右子树的时候 结束为止不变,开始位置为 根节点 + 1

所以我们这里要特别注意一下。那么我们接下来看看代码如何编写: 

   ▶ 代码:

class Solution {
    public  int preorderIndex;//这个就是 i 这个下标

    public TreeNode buildTree(int[] preorder, int[] inorder) {

        return buildTreeChild(preorder,inorder,0,inorder.length - 1);
    }

    public TreeNode buildTreeChild(int[] preorder,int[] inorder,int ib,int ie) {
        //结束条件
        if (ib > ie) {
            return null;
        }

        //设置先序遍历的根节点
        TreeNode root = new TreeNode(preorder[preorderIndex]);

        //找我们先序遍历的 i 下标这个节点在 中序遍历的位置
        int rootindex = findval(inorder,ib,ie,preorder[preorderIndex]);

        //找完之后我们要把 i 下标增加一位
        preorderIndex++;

        //递归设置左子树的节点
        root.left = buildTreeChild(preorder,inorder,ib,rootindex - 1);
        //递归设置右子树的节点
        root.right = buildTreeChild(preorder,inorder,rootindex + 1,ie);

        return root;
    }

    public int findval(int[] inorder,int ib,int ie,int val){

        for (int i = ib; i <= ie; i++) {
            if (inorder[i] == val) {
                return i;
            }
        }
        return -1;
    }
}

Ok啊,这个题呢就结束了,我们在来看看下一个题。


❄️四、习题四(从中序和后序遍历序列中构造二叉树):

          ☞  题的链接:

                       从中序和后序遍历序列中构造二叉树


     ▶ 思路:

    当我们理解我们上面的 从先序和中序遍历创建二叉树 的话呢,那么我们在做这道题的时候呢就非常的容易了,我们的 中序遍历:左 根 右   后序遍历:左  右  根。

    我们在这里利用 后序遍历来找根节点,就是我们 后序遍历的最后一个节点,之后我们从后往前走,就是变成 先创建右子树 再创建左子树。

     因为思路是差不多的,所以我们直接来看看代码是如何编写的:

    ▶ 代码:

class Solution {
    public int postorderInder;

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        postorderInder = postorder.length - 1;// 最后一个数据的下标
        return buildTreeChild(inorder, postorder, 0, inorder.length - 1);
    }

    public TreeNode buildTreeChild(int[] inorder, int[] postorder, int ib, int ie) {
        if (ib > ie) {
            return null;
        }

        TreeNode root = new TreeNode(postorder[postorderInder]);

        int rootIndex = findval(inorder, postorder[postorderInder], ib, ie);

        postorderInder--;

        root.right = buildTreeChild(inorder, postorder, rootIndex + 1, ie);

        root.left = buildTreeChild(inorder, postorder, ib, rootIndex - 1);

        return root;
    }

    public int findval(int[] inorder, int val, int ib, int ie) {

        for (int i = ib; i <= ie; i++) {
            if (inorder[i] == val) {
                return i;
            }
        }
        return -1;
    }
}

OK,我们的这道题也到这里就结束了,我们来看看这篇博客的最后一道题了。 


❄️五、习题五(根据二叉树创建字符串):

          ☞  题的链接:

                       根据二叉树创建字符串


       ▶ 思路:

    我们这个题呢,我们开始直接放入我们根的节点,之后当我们来看左子树如何操作:

    左子树不为空 的时候我们先添加一个 '('  之后我们添加数据,添加之后我们再添加 ')' ,

    左子树为空 的话,我们还要判断一下其右子树为不为空,如果为空就直接退出,不为空就直接                         添加 '()' 

右子树如何操作:

    右子树不为空的话 我们还是执行先添加一个 '(' 之后添加数据,之后是 ')'

    右子树为空的话   我们直接退出就可以了,因为这里我们已经判断完了左子树,左子树为空,我们才退出的判断左子树,才能判断右子树,所以这里我们为空时,直接退出就可以了。

这里注意我们的字符串使用 StringBuilder 来进行字符串的连接。

我们来看看图,更加直观的了解一下: 

我们再来看看另一种情况: 

 我们按照这个思路进行编写代码就可以了,我们来看看如何进行编写的:

     ▶ 代码:

public String tree2str(TreeNode root) {
        if (root == null) {
            return null;
        }
        //StringBuilder是可以把字符串连接起来的
        StringBuilder stringBuilder = new StringBuilder();

        tree2strChild(root, stringBuilder);

        return stringBuilder.toString();
    }

    public void tree2strChild(TreeNode root, StringBuilder stringBuilder) {
        if (root == null) {
            return;
        }
        //对于根节点我们直接放入
        stringBuilder.append(root.val);

        if (root.left != null) {
            stringBuilder.append('(');
            tree2strChild(root.left, stringBuilder);
            stringBuilder.append(')');
        } else {

            if (root.right == null) {
                return;
            } else {
                stringBuilder.append("()");
            }
        }

        if (root.right != null) {
            stringBuilder.append('(');
            tree2strChild(root.right, stringBuilder);
            stringBuilder.append(')');
        } else {

            return;
        }

    }

OK,代码到这里就结束了,我们这道题也就结束了。


❄️六、总结:

      OK啦,今天的练习题呢就到这里就结束了,还是那句话,对于二叉树的题,我们要时刻记住递归的性质与应用。今天的题呢还是比较难理解的,我们一定要配合着画图去理解。 让我们期待下一篇博吧!!!拜拜~~~

 

标签:遍历,Java,int,节点,二叉树,return,习题,root,我们
From: https://blog.csdn.net/2303_80388948/article/details/142217099

相关文章

  • JavaSE——多线程
    一、线程的五种基本状态1.新建状态(New)创建一个线程对象后,该线程对象就处于新建状态。此时它不能运行,仅仅是Java虚拟机为其分配了内存。2.就绪状态(Runnable)当线程对象调用的start()方法后,该线程就进入就绪状态。处于就绪状态的线程位于线程队列中,等待系统的调度以获得CPU的......
  • 使用 O(1) 额外内存删除二叉树
    这是一个naive的做法:voiddeleteTreeRec(TreeNode*root){if(root==NULL)return;deleteTreeRec(root->left);deleteTreeRec(root->right);cout<<"Deletingnode"<<root->data<<endl;deleteroot;}O(1)空......
  • Java【集合】
    一、集合的概述集合建立在数组基础上,主要位于java.util包中,用来存储Java类对象,并且可以实现各种数据结构。集合大小可以改变,可以存放不同数据类型数据。集合不能存放基本类型数据,只能存放引用数据类型数据。集合不仅可以方便地存放数据,而且提供了添加、读取和删除数据等实用......
  • springboot基于java的医陪人员招聘系统(源码+java+vue+部署文档+讲解等)
    收藏关注不迷路!!......
  • Java 锁实现
    在Java中,锁有多种实现方式,主要包括以下几种:一、synchronized关键字1.作用于方法   同步实例方法:通过在实例方法上使用synchronized关键字,锁对象是当前实例对象(this)。确保在同一时刻,只有一个线程可以执行该实例方法。   同步静态方法:在静态方法上使用synchroniz......
  • 深入理解 ECMAScript 和 JavaScript
    目录ECMAScript是什么?JavaScript是什么?示例ECMAScript示例JavaScript示例总结ECMAScript是什么?ECMAScript是一个由国际标准化组织ECMA(欧洲计算机制造商协会)维护的脚本语言标准。这个标准定义了一种脚本语言的基本特性,包括语法、类型系统、内置对象、关键字等......
  • Java Web项目使用注解和面向切面编程优雅的记录操作日志
    1.背景在我们的项目中,记录模块的操作日志比较麻烦,需要通过定义对象,获取需要记录的日志内容,最后插入到日志操作表等一系列动作才能完成。该方案既笨拙,使用也不方便,使得代码中存在大量冗余。因此,想要找到一种方便又优雅的方案解决该问题,使得日志模块既不影响业务逻辑的执行,又能......
  • 力扣热题100 - 二叉树:二叉搜索树中第 K 小的元素
    题目描述:题号:230给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从1开始计数)。解题思路:思路一:中序遍历二叉树+ 计数根据二叉搜索树的性质,中序遍历得到的节点的顺序是从小到大递增的。所以可以一边中序遍历,一边计数......
  • 力扣热题100 - 二叉树:二叉树展开为链表
    题目描述:题号:114给你二叉树的根结点 root ,请你将它展开为一个单链表:展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同。解题思路:思路一:前序遍历后......
  • Java:继承和多态(2)
    一super关键词在JavaSE中,super是一个非常重要的关键字,用于引用父类(超类)的构造方法、字段或方法。1.调用父类的构造方法publicclassAnimal{publicStringname;publicintage;publicAnimal(Stringname,intage){this.name=name;......