【数据结构】 二叉树面试题讲解->贰

news2024/11/16 1:55:49

文章目录

  • 🌏引言
  • 🎄[二叉树遍历](https://www.nowcoder.com/practice/4b91205483694f449f94c179883c1fef?tpId=60&&tqId=29483&rp=1&ru=/activity/oj&qru=/ta/tsing-kaoyan/question-ranking)
    • 🐱‍👤题目描述:
      • 📌输入描述:
      • 📌输出描述:
    • 🐱‍🐉示例:
    • 🐱‍👓思路解析:
    • 🐱‍🏍完整代码实现:
  • 🌳[二叉树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/description/)
    • 🐱‍👤题目描述:
    • 🐱‍🐉示例:
      • 📌示例一
    • 📌示例二
    • 🐱‍👓思路解析
      • 🚩思路一
    • 🚩思路二
    • 🐱‍🏍代码实现:
      • 🎈思路一代码实现
      • 🎈思路二代码实现
  • 🎍[从前序与中序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/)
    • 🐱‍👤题目描述
    • 🐱‍🐉示例:
    • 🐱‍👓思路解析:
    • 🐱‍🏍代码实现:
  • 🌲拓展——[从中序与后序遍历序列构造二叉树](https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/%E3%80%81)
  • ⭕总结

🌏引言

二叉树的操作算法是笔试面试中较为常见的题目。
本文将着重介绍平时面试中常见的关于二叉树的应用题目,马上要进行秋招了。希望对你们有帮助 _😀
在这里插入图片描述

🎄二叉树遍历

🐱‍👤题目描述:

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

📌输入描述:

输入包括1行字符串,长度不超过100。

📌输出描述:

可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。

🐱‍🐉示例:

输入: abc##de#g##f###
输出:c b e g d f a

🐱‍👓思路解析:

首先我们先来看一下示例输入的二叉树的形状
在这里插入图片描述
我们首先需要做的是创建一个二叉树类,用于建立一个新的二叉树

class TreeNode1 {
    char val;
    TreeNode1 left;
    TreeNode1 right;
    TreeNode1() {}
    TreeNode1(char val) {
        this.val = val;
    }
    TreeNode1(char val, TreeNode1 left, TreeNode1 right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

接下来我们需要

  • 依旧采用递归的思想
  • 对字符串的每一个元素进行遍历,并进行判断
  • 在遍历时,我们创建一个静态变量为size,此后每遍历一个元素,size就++
  • 若不为’#',则该结点设为根节点
  • 并且size++;
  • 然后因为是前序遍历,所以根节点后面应该是左子树,然后是右子树
  • 若为’#',则该节点为null,我们只需要size++即可
  • 最后返回该结点就好

代码实现如下:

    public static TreeNode1 creatTree(String str) {
        TreeNode1 root = null;
        if (str.charAt(i) != '#') {
            root = new TreeNode1(str.charAt(i));
            i++;
            root.left = creatTree(str);
            root.right = creatTree(str);
        } else {
            i++;
        }
        return root;
    }

然后根据题意我们还需要进行一个中序遍历,这里我就不做赘述了,又不懂的小伙伴可以去看一下博主对于【数据结构】二叉数的存储与基本操作的实现的讲解

实现如下:

public static void inorder(TreeNode1 root) {
        if (root == null) {
            return;
        }
        inorder(root.left);
        System.out.print(root.val + " ");
        inorder(root.right);
    }
}

🐱‍🏍完整代码实现:

import java.util.Scanner;
class TreeNode1 {
    char val;
    TreeNode1 left;
    TreeNode1 right;
    TreeNode1() {}
    TreeNode1(char val) {
        this.val = val;
    }
    TreeNode1(char val, TreeNode1 left, TreeNode1 right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}
public class Main {

    public static int i = 0;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            i = 0;
            String st = in.nextLine();
            TreeNode1 root = new TreeNode1();
            root = creatTree(st);
            inorder(root);
        }
    }
    public static TreeNode1 creatTree(String str) {
        TreeNode1 root = null;
        if (str.charAt(i) != '#') {
            root = new TreeNode1(str.charAt(i));
            i++;
            root.left = creatTree(str);
            root.right = creatTree(str);
        } else {
            i++;
        }
        return root;
    }
    public static void inorder(TreeNode1 root) {
        if (root == null) {
            return;
        }
        inorder(root.left);
        System.out.print(root.val + " ");
        inorder(root.right);
    }
}

🌳二叉树的最近公共祖先

🐱‍👤题目描述:

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

    }

🐱‍🐉示例:

📌示例一

在这里插入图片描述

📌示例二

在这里插入图片描述

🐱‍👓思路解析

本题博主提供两种解题思路

🚩思路一

我们发现:

  • 如果p,q不是根节点,且p,q一个在左子树被找到,一个在右子树被找到
  • 那么该根节点为最近公共祖先
  • 在这里插入图片描述
  • 若该根节点为p或者q,那么自身则为最近祖先
    在这里插入图片描述
    若最后都没有找到,说明没有,返回空

🚩思路二

我们建立两个栈:

  • 栈1用于存储找到p结点的路径
  • 栈2用于存储找到q结点的路径
    在这里插入图片描述
  • 然后我们对两个栈求长度,把栈长度比较长的栈进行出栈,直到两个栈长度相等
  • 然后同时出栈进行一一比对,相同则为p、q的最近公共祖先
    在这里插入图片描述
    这种思路的解题难点在于如何找到p、q的路径并放入栈中,博主采用的做法如下:
  • 首先我们对二叉树与所找p、q结点进行判断
  • 若为空返回false
  • 然后我们需要对当前根节点进行判断,若为我们要找的p或q
  • 则返回true
  • 若没有我们便对该根节点的左子树进行入栈并进行判断,若找到返回true
  • 若没有找到则将该左子树进行出栈
  • 然后对右子树进行同样操作
  • 最后若都没找到,返回false

然后我们只需要对两栈元素进行出栈进行比对就好了,最先相等的就为我们的最近公共祖先

🐱‍🏍代码实现:

🎈思路一代码实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(p == root || q == root) {
            return root;
        }
        if(root == null) {
            return null;
        }
        TreeNode l = lowestCommonAncestor(root.left,p,q);
        TreeNode r = lowestCommonAncestor(root.right,p,q);
        if(l != null && r != null) {
            return root;
        } else if(l != null) {
            return l;
        } else if(r != null) {
            return r;
        }
        return null;
    }
}

🎈思路二代码实现

class Solution {
        public boolean getPath(TreeNode root, TreeNode node,
                           Deque<TreeNode> stack) {
        if(root == null || node == null)return false;
        stack.push(root);
        //放完之后 要检查
        if(root == node) return true;
        boolean ret1 = getPath(root.left,node,stack);
        if(ret1) return true;
        boolean ret2 = getPath(root.right,node,stack);
        if(ret2) return true;
        stack.pop();
        return false;
    }
    public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
        //1、两个栈当中 存储好数据
        Deque<TreeNode> stack1 = new LinkedList<>();
        getPath(root,p,stack1);
        Deque<TreeNode> stack2 = new LinkedList<>();
        getPath(root,q,stack2);
        //2、判断栈的大小
        int size1 = stack1.size();
        int size2 = stack2.size();
        if(size1 > size2) {
            int size = size1-size2;
            while (size != 0) {
                stack1.pop();
                size--;
            }
        }else {
            int size = size2-size1;
            while (size != 0) {
                stack2.pop();
                size--;
            }
        }
        //栈里面数据的个数 是一样的
        while (!stack1.isEmpty() && !stack2.isEmpty()) {
            if(stack1.peek() != stack2.peek()) {
                stack1.pop();
                stack2.pop();
            }else {
                return stack1.peek();
            }
        }
        return null;
    }
}

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

🐱‍👤题目描述

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

/**
 * 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 TreeNode buildTree(int[] preorder, int[] inorder) {

    }
}

🐱‍🐉示例:

在这里插入图片描述

🐱‍👓思路解析:

我们知道前序遍历里面第一个存储的是我们的根节点

那我们就可以在我们中序遍历中找到该结点,则该结点两边就为该根节点的左右子树
对于任意一颗树而言,前序遍历的形式总是

[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]

即根节点总是前序遍历中的第一个节点。而中序遍历的形式总是

[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]

只要我们在中序遍历中定位到根节点,那么我们就可以分别知道左子树和右子树中的节点数目。由于同一颗子树的前序遍历和中序遍历的长度显然是相同的,因此我们就可以对应到前序遍历的结果中,对上述形式中的所有左右括号进行定位。

这样以来,我们就知道了左子树的前序遍历和中序遍历结果,以及右子树的前序遍历和中序遍历结果,我们就可以递归地对构造出左子树和右子树,再将这两颗子树接到根节点的左右位置。

我们的做法是这样的

  • 我们对前序遍历结果进行下标利用下标 i 遍历,并放入到二叉树中

  • 在这里插入图片描述

  • 对中序遍历的元素设两个下标,一个记录最左边,一个记录最右边

  • 在这里插入图片描述

  • 对前序遍历里的每一个元素我们会在中序遍历里进行查找,找到后

  • 我们的inbegin与inend在左右子树里又会有新的指向

  • 在这里插入图片描述

  • 然后我们利用递归的思想,对所有元素进行遍历

  • 结束条件为inend < inbengin

  • 在这里插入图片描述

🐱‍🏍代码实现:

/**
 * 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 int i = 0;
    public TreeNode buildTree(int[] preorder, int[] inorder) {

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

    public TreeNode buildTreeChild(int[] preorder, int[] inorder,
    int inbegin,int inend) {
        if(inbegin > inend) {
            return null;
        }
        TreeNode root = new TreeNode(preorder[i]);
        //找到当前根,在中序遍历的位置
        int rootIndex = findIndex(inorder,inbegin,inend,preorder[i]);
        i++;
        root.left = buildTreeChild(preorder,inorder,inbegin,rootIndex-1);
        root.right = buildTreeChild(preorder,inorder,rootIndex+1,inend);
        return root;
    }

    private int findIndex( int[] inorder,int inbegin,int inend, int key) {
        for(int i = inbegin;i <= inend; i++) {
            if(inorder[i] == key) {
                return i;
            }
        }
        return -1;
    }
}

🌲拓展——从中序与后序遍历序列构造二叉树

与从前序与中序遍历序列构造二叉树实现类似,这里不再做过多赘述

代码实现:

    class Solution2 {
        public int i = 0;
        public TreeNode buildTree(int[] inorder, int[] postorder) {
            i = postorder.length-1;
            return buildTreeChild(postorder,inorder,0,inorder.length-1);
        }

        public TreeNode buildTreeChild(int[] postorder, int[] inorder,
                                       int inbegin,int inend) {
            if(inbegin > inend) {
                return null;
            }
            TreeNode root = new TreeNode(postorder[i]);
            //找到当前根,在中序遍历的位置
            int rootIndex = findIndex(inorder,inbegin,inend,postorder[i]);
            i--;
            root.right = buildTreeChild(postorder,inorder,rootIndex+1,inend);
            root.left = buildTreeChild(postorder,inorder,inbegin,rootIndex-1);
            return root;
        }

        private int findIndex( int[] inorder,int inbegin,int inend, int key) {
            for(int i = inbegin;i <= inend; i++) {
                if(inorder[i] == key) {
                    return i;
                }
            }
            return -1;
        }
    }

⭕总结

关于《【数据结构】 二叉树面试题讲解->贰》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/963819.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里云短信服务测试

测试时遇到下面的错误; {"Message":"测试专用签名和模板必须结合使用","RequestId":"59035729-FD2A-5618-A2BE-6CABD839B400","Code":"isv.SMS_TEST_SIGN_TEMPLATE_LIMIT"} 上网查了下才发现&#xff1a; 使用…

一些自己整理的工具实用参数

工具实用参数 sqlmap -u: 指定需要测试的目标URL&#xff08;格式&#xff1a;http://www.example.com/test.php?id1&#xff09; --cookie: 设置需要发送的 HTTP Cookie&#xff0c;例如&#xff1a;--cookie"sid123456;PHPSESSID654321" --threads&#xff1a;…

化学中的各种基团(羧基、酰胺、吡喃、联苯结构)

一、羧基 化学式–C(O)OH&#xff0c;是羧酸所具有的官能团。一般而言&#xff0c;羧基上的氢有较大的电离倾向&#xff0c;从而使羧酸在水溶液中显酸性。羧酸根负离子所具有共轭结构可以看作是氢易电离的潜在动力。 二、羟基 化学式&#xff0d;OH&#xff0c;是氧原子以共价…

nginx的配置文件

nginx的配置文件 一、nginx配置文件1.1、主配置文件详解1.2、子配置文件 二、修改启动程序的全局配置2.1、修改启动的工作进程数优化2.2、cpu与eorker process绑定优化2.3、PID路径优化2.4、修改工作进程的优先级 优化2.5、调试工作进程打开文件的文件个数2.5.1、基本原理2.5.2…

ac7260网卡不能连5g

之前路由器是双频&#xff0c;最近为了连物联网一堆&#xff0c;把双频拆成两个wifi 结果电脑上装的pdd网卡就罢工了&#xff0c;连4g可以&#xff0c;但是连5g网络就不行&#xff0c;连上却没网&#xff0c;导致网盘下东西慢。刚开始以为是tplink的易展问题&#xff0c;结果看…

Python Opencv实践 - 凸包检测(ConvexHull)

import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/stars.png") plt.imshow(img[:,:,::-1])img_contour img.copy() #得到灰度图做Canny边缘检测 img_gray cv.cvtColor(img_contour, cv.COLOR_BGR2GRAY) edges…

Python将多个文件的名称或后缀名由大写字母修改为小写的方法

本文介绍基于Python语言&#xff0c;基于一个大文件夹&#xff0c;遍历其中的多个子文件夹&#xff0c;并对于每一个子文件夹中的大量文件&#xff0c;批量将其文件的名称或后缀名中的字母由大写修改为小写的方法。 本文期望实现的需求为&#xff1a;现有一个大文件夹&#xff…

netcat的使用

目录 netcat简介 nc的使用场景 nc实现通信 创建一个服务端 创建一个客户端 具体案例 环境 win10在具体路径下执行命令 win7在具体路径下执行命令 netcat文件传输 nc文件传输的利用 服务器等待接收文件 客户端向服务器发送文件 服务器向连接的客户端发送文件 客户…

内网隧道代理技术(二十)之 CS使用HTTP代理上线不出网机器

CS使用HTTP代理上线不出网机器 CS工具自带上线不出网机器 如图A区域存在一台中转机器,这台机器可以出网,这种是最常见的情况。我们在渗透测试的过程中经常是拿下一台边缘机器,其有多块网卡,边缘机器可以访问内网机器,内网机器都不出网。这种情况下拿这个边缘机器做中转,…

OpenSIPS 管理接口的对接

文章目录 1. 背景2. OpenSIPS 的 HTTP 管理接口对接2.1 脚本配置2.2 请求方式 1. 背景 OpenSIPS 是功能完善的开源 SIP 代理服务器&#xff0c;它在支持 SIP 代理的主要功能以外&#xff0c;也为使用者提供了一套 MI 管理接口。面向不同的通信方式&#xff0c;OpenSIPS 还提供…

训练简单的线性模型,预测电影评分和票房收入

文章目录 训练简单的线性模型&#xff0c;预测电影评分和票房收入数据集加载数据可视化数据分割数据集训练模型可视化结果应用模型保存和加载模型 训练简单的线性模型&#xff0c;预测电影评分和票房收入 这是一个简单的线性模型&#xff0c;用于预测电影的评分和票房收入。不…

Mysql 性能分析(慢日志、profiling、explain)、读写分离(主从架构)、分库分表(垂直分库、垂直分表、水平分表)

查看系统性能参数 一条sql查询语句在执行前&#xff0c;需要确定查询执行计划&#xff0c;如果存在多种执行计划的话&#xff0c;mysql会计算每个执行计划所需要的成本&#xff0c;从中选择 成本最小的一个作为最终执行的执行计划 想要查看某条sql语句的查询成本&#xff0c;可…

【LeetCode算法系列题解】第21~25题

CONTENTS LeetCode 21. 合并两个有序链表&#xff08;简单&#xff09;LeetCode 22. 括号生成&#xff08;中等&#xff09;LeetCode 23. 合并K个升序链表&#xff08;困难&#xff09;LeetCode 24. 两两交换链表中的节点&#xff08;中等&#xff09;LeetCode 25. K 个一组翻转…

Python 中的类,包括self关键字、类的属性限制访问

Python 中的类 一 、类和对象1.概念2.写法&#xff1a; 二、 self用法详解1.self代表类的实例&#xff0c;而非类2.self可以不写吗&#xff1f;3.在继承时&#xff0c;self的使用。 三、 属性限制访问1. 系统定义2.保护类型成员3.私有类型成员 一 、类和对象 1.概念 类是封装…

房屋装修选择自装,如何寻找木工师傅,比价全屋定制和木工并施工(木工阶段)

环境&#xff1a; 地点&#xff1a;杭州 装修类型&#xff1a;自装 面积&#xff1a;建面135平方 进度&#xff1a;木工阶段 问题描述&#xff1a; 房屋装修选择自装&#xff0c;如何寻找木工师傅&#xff0c;比价全屋定制和木工并施工&#xff08;木工阶段&#xff09; …

SpringBoot项目通过分词器生成词云

目录 前言一、词云是什么&#xff1f;二、使用步骤1.引入依赖2.application.yml3.Controller4.分词工具类4.词云生成工具类、支持输出文件和字节流 注意 前言 公司项目涉及到员工任务管理&#xff0c;需要从员工任务中获取任务信息生成个人词云图&#xff0c;可以把员工任务中…

【小沐学Unity3d】3ds Max 骨骼动画制作(CAT、Character Studio、Biped、骨骼对象)

文章目录 1、简介2、 CAT2.1 加载 CATRig 预设库2.2 从头开始创建 CATRig 3、character studio3.1 基本描述3.2 Biped3.3 Physique 4、骨骼系统4.1 创建方法4.2 简单示例 结语 1、简介 官网地址&#xff1a; https://help.autodesk.com/view/3DSMAX/2018/CHS https://help.aut…

Python基础之基础语法(二)

Python基础之基础语法(二) 语言类型 静态语言 如&#xff1a;C C Java ina a 100 a 100 a abc # 不可以静态语言需要指定声明标识符的类型&#xff0c;之后不可以改变类型赋值。静态语言变异的时候要检查类型&#xff0c;编写源代码&#xff0c;编译时检查错误。 动态语…

jupyter常用的方法以及快捷键

选中状态 蓝色 按enter 进入编辑状态 编辑状态 绿色 按Esc 进入选中状态 Code模式运行是运行代码 Markdown模式运行是进入预览状态 - - - 是文本格式的一种精简的语法形式 Raw NBConvert 是默认文本状态 - - - 输入什么样 展示什么样 Y - - - 切换code模式 M - - - 切换Markdo…

01-虚拟机安装Windows Server操作系统

1、创建并配置虚拟机 2、安装操作系统 找到windows Server镜像 等待安装 3、设置密码