《数据结构》二叉树面试题

news2024/9/28 1:16:56

👑作者主页:Java冰激凌
📖专栏链接:数据结构  

目录

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

思路分析

代码

思路拓展

根据一棵树的前序遍历与中序遍历构造二叉树。力扣

思路分析

代码

根据一棵树的中序遍历与后序遍历构造二叉树 力扣

思路分析

 代码

二叉树创建字符串力扣 

思路分析

代码

思路拓展

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

思路分析

 对于此题 我们的思路是要借助要另一个数据结构 就是我们的栈

首先我们先来分析一波 他可能出现的情况

1.其中一个节点是最近的祖先节点  所以说我们的节点3就是我们的最近祖先节点

 2.其中一个节点是另一个节点的祖先节点 所以说 我们的5节点是最近的祖先节点

 3.最近公共祖先是根节点

 我们的思路大概如下:将从根节点到子节点的所有节点都保存到栈中 然后比较两个栈的长度 让栈长度长的先出掉对应个元素 到两个栈节点数量相同时 两个栈同时出节点 当出到了相同节点的时候 这个节点就是我们的最近公共祖先了~

首先我们来将两个节点的路径分别保存到栈中(我们采取先序遍历的思路保存节点)

我们再将两个栈的长度进行对比 长度长的栈先出对应个数的节点 然后我们再同时出节点 直到两个节点相同为止(其中要多考虑的一步是 如果其中一个栈为空 那么代表没有找到对应的节点~ 不过题目中是给出了保证存在的 所以这一步可以不考虑)

 

代码

public boolean addStack(TreeNode root,Stack<TreeNode> stack, TreeNode node){
        if(root == null || node == null){
            return false;
        }
        stack.push(root);
        if(root == node){
            return true;
        }
        boolean ret1 = addStack(root.left,stack,node);
        if(ret1){
            return true;
        }
        boolean ret2 = addStack(root.right,stack,node);
        if(ret2){
            return true;
        }
        stack.pop();
        return false;
    }
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        Stack<TreeNode> stackp = new Stack<>();
        Stack<TreeNode> stackq = new Stack<>();
        addStack(root,stackp,p);
        addStack(root,stackq,q);
        //计算两个栈的长度
        int len1 = stackp.size();
        int len2 = stackq.size();
        if(len1 > len2){
            while(len1 - len2 > 0){
                len1--;
                stackp.pop();
            }
        }else {
            while(len2 - len1 > 0){
                len2--;
                stackq.pop();
            }
        }
        while(true){
            if(stackp.isEmpty()||stackq.isEmpty()){
                break;
            }
            if(stackp.peek() == stackq.peek()){
                return stackp.peek();
            }
            stackp.pop();
            stackq.pop();
        }
        return null;
    }

算法分析:时间复杂度O(N) 空间复杂度O(N) 

思路拓展

提供一个新的思路  我们之前提到过的  树的题一般都是用递归来解的 我们考虑节点是否存在左子树或者右子树 当节点都存在于一颗树的左右子树的时候 那么这个根就是最近公共祖先节点(ps:对于递归的代码 我们要进行划分子问题 学会将一个问题转化为简单问题 并且在思考递归问题的时候

要学会纵向思考 不要将递归展开来想 将递归展开是想不出来的)

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q){
            return root;
        }
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        if(left != null && right != null){
            return root;
        }
        if(left == null){
            return right;
        }
        return left;
    }

算法分析:时间复杂度O(N) 空间复杂度O(N) 


根据一棵树的前序遍历与中序遍历构造二叉树。力扣

思路分析

做这道题我们首先需要之前的博客为支撑《数据结构》二叉树(基础题)_Java冰激凌的博客-CSDN博客二叉树基础题https://blog.csdn.net/m0_69996872/article/details/128822826?spm=1001.2014.3001.5501我们先要熟系给定一颗先序遍历树和一颗中序遍历是如何构造一颗二叉树的

 我们可知 先序遍历的第一个为根节点 所以我们可以根据这个特性出发 在中序遍历中找到该节点所在位置  找到所在位置后 根据我们之前学到的 在这个节点的左边 都为左子树 右边的都为右子树 所以说 我们可以按照这个思路来分割为递归问题

 我们只要按照这个思路依次往下遍历即可~ 是不是恍然大悟!

代码

private int i = 0;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder == null || inorder == null){
            return null;
        }
        return counst(preorder,inorder,0,inorder.length-1);
    }
    
    public TreeNode counst(int[] preorder,int[] inorder,int s1,int s2){
        if(s1 > s2){
            return null;
        }
        TreeNode node = new TreeNode(preorder[i]);
        int index = findIndex(inorder,s1,s2,preorder[i]);
        if(index == -1){
            return null;
        }
        i++;
        node.left = counst(preorder,inorder,s1,index-1);
        node.right = counst(preorder,inorder,index+1,s2);
        return node;
    }
    public int findIndex(int[] inorder,int s1,int s2,int val){
        for(int j = s1; j <= s2;j++){
            if(inorder[j] == val){
                return j;
            }
        }
        return -1;
    }

算法分析:时间复杂度O(N) 空间复杂度O(N)


根据一棵树的中序遍历与后序遍历构造二叉树 力扣

思路分析

这个题跟我们刚刚做的一道有异曲同工之妙 我们还是要先有中序遍历和后序遍历绘制二叉树的基础 首先我们知道 后序遍历的最后一个是根节点 所以我们要从最后一个节点出发 所以此处的i就要从最后往前走 其中需要注意到的是 因为后序遍历的是左右根 所以我们在构造的时候 需要先构造右子树再构造左子树

 代码

private int i = 0;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        if(inorder == null || postorder == null){
            return null;
        }
        i = inorder.length - 1;
        return counst(inorder,postorder,0,inorder.length-1);
    }
    public TreeNode counst(int[] inorder,int[] postorder,int s1,int s2){
        if(s1 > s2){
            return null;
        }
        TreeNode node = new TreeNode(postorder[i]);
        int index = findIndex(inorder,postorder[i],s1,s2);
        if(index == -1){
            return null;
        }
        i--;
        node.right = counst(inorder,postorder,index+1,s2);
        node.left = counst(inorder,postorder,s1,index-1);
        return node;
    }
    public int findIndex(int[] inorder,int val,int s1,int s2){
        for(int j = s1;j <= s2; j++){
            if(inorder[j] == val){
                return j;
            }
        }
        return -1;
    }

算法分析:时间复杂度O(N) 空间复杂度O(N)


二叉树创建字符串力扣 

思路分析

我们可以先来观察题目

 首先我们可以得知~ 当我们左子树或者右子树有节点的时候 我们都需要将值放入括号中

所以我们可以适当的添加判断 当左子树不为空的时候 先添加左括号 当遍历完之后 回到本次递归的时候 继续判断左子树不为空的时候 添加右括号 右子树也是同理

我们来看一下第二个实例

 当左子树为空 但右子树不为空的时候  我们是需要适当的添加一对括号的 否则会破坏输入和输出的映射关系

代码

 public void _tree2str(TreeNode root,StringBuilder str){
        if(root == null){
            return ;
        }
        str.append(root.val);
        if(root.left != null){
            str.append("(");
        }
        _tree2str(root.left,str);
        if(root.left != null){
            str.append(")");
        }
        if(root.left == null && root.right != null){
            str.append("()");
        }
        if(root.right != null){
            str.append("(");
        }
        _tree2str(root.right,str);
        if(root.right != null){
            str.append(")");
        }
    }
    public String tree2str(TreeNode root) {
        StringBuilder str = new StringBuilder();
        _tree2str(root,str);
        return str.toString();
    }

算法分析:时间复杂度O(N) 空间复杂度O(N)

思路拓展

        面试官说: 不错 递归遍历写的不错 你能用非递归遍历来做吗?

        好的 我们以下的思路首先是最简单的将递归转为非递归的思路 其中我们需要多考虑一个 就是如果使用非递归的话  会存在一个节点被遍历两次 那么这个情况应该如何避免呢 这个时候就需要借助到我们的Set 来做到一个去重  其中一个对于set去重的判断巧用了set.add 返回类型为boolean 如果成功放入返回true 如果失败返回false 还有要注意到的是 我们在头节点的时候 是不需要加左右括号的 所以我们为了方便处理 直接加入判断即可

public String tree2str(TreeNode root) {
        StringBuilder str = new StringBuilder();
        Stack<TreeNode> stack = new Stack<>();
        Set<TreeNode> set = new HashSet<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.peek();
            if(!set.add(node)){
                if(node != root){
                    str.append(")");
                }
                stack.pop();
            }else {
                if(node != root){
                    str.append("(");
                }
                str.append(node.val);
                if(node.right != null){
                    stack.push(node.right);
                }
                if(node.left != null){
                    stack.push(node.left);
                }else if(node.right != null){
                    str.append("()");
                }
            }
        }
        return str.toString();
    }

 算法分析:时间复杂度O(M+N) 空间复杂度O(N)

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

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

相关文章

Linux系统看门狗应用编程

目录看门狗应用编程介绍打开设备获取设备支持哪些功能&#xff1a;WDIOC_GETSUPPORT获取/设置超时时间&#xff1a;WDIOC_GETTIMEOUT、WDIOC_SETTIMEOUT开启/关闭看门狗&#xff1a;WDIOC_SETOPTIONS喂狗&#xff1a;WDIOC_KEEPALIVE看门狗应用编程实战在产品化的嵌入式系统中&…

[计算机网络(第八版)]第二章 物理层(章节测试/章节作业)

章节作业 带答案版 选择题 (单选题)双绞线是用两根绝缘导线绞合而成的&#xff0c;绞合的目的是&#xff08; &#xff09;。 A. 减少干扰 B. 提高传输速度 C. 增大传输距离 D. 增大抗拉强度(单选题)在电缆中采用屏蔽技术可以带来的好处主要是&#xff08; &#xff09;。 A…

DNS 域名解析

介绍域名 网域名称&#xff08;英语&#xff1a;Domain Name&#xff0c;简称&#xff1a;Domain&#xff09;&#xff0c;简称域名、网域。 域名是互联网上某一台计算机或计算机组的名称。 域名可以说是一个 IP 地址的代称&#xff0c;目的是为了便于记忆。例如&#xff0c…

Latex中的表格(2)

Latex中的表格一、一个加脚注的三线表的例子二、一个表格中加注释的例子三、两个并排的两个表格的例子3.1 使用小页环境并排表格3.2 使用子表格并排表格四、一个格式复杂的表格的例子五、一个长表格的例子这篇文章主要罗列一些特殊的表格例子。内容来自&#xff1a;一篇北师大学…

深度剖析数据在内存的存储

目录1.深度剖析数据在内存的存储(前言)数据类型介绍类型的基本归类整形在内存中的存储原码、反码、补码大小端练习总结1.深度剖析数据在内存的存储(前言) 今天就让我戴佳伟给大家讲一下数据在内存中的存储。之中有好多让我们深思的点&#xff0c;大家都拿起笔记本&#xff0c;…

【机器学习笔记】Python基础笔记

目录基础语法加载数据&#xff1a;pd.read_csv查看数据大小&#xff1a;shape浏览数据行字段&#xff1a;columns浏览少量数据&#xff1a;head()浏览数据概要&#xff1a;describe()基础功能语法缺省值去除缺失值&#xff1a;dropna按行删除&#xff1a;存在空值&#xff0c;即…

【数据库】第二章 关系数据库

第二章 关系数据库 2.1关系数据结构及形式化定义 关系 域&#xff08;domain) :域是一组具有相同数据类型的值的集合&#xff0c;可以取值的个数叫基数 笛卡尔积 &#xff1a;一个记录叫做一个元组&#xff08;tuple),元组中每一个属性值&#xff0c;叫一个分量 基数&…

35测试不如狗?是你自己技术不够的怨怼罢了

一、做软件测试怎么样&#xff1f; 引用著名软件测试专家、清华大学郑人杰教授的说法&#xff1a;软件测试工程师是一个越老越吃香的职业。 其中就表达了软件测试工作相对稳定、对年龄没有限制、而且随着项目经验的不断增长和对行业背景的深入了解&#xff0c;会越老越吃香。…

刚上岸字节测试开发岗,全网最真实的大厂面试真题

首先我来解释一下为什么说是全网最真实的面试题&#xff0c;相信大家也发现软件测试面试题在网上流传也已不少&#xff0c;但是经过仔细查看发现了两个很重要的问题。 第一&#xff0c;网上流传的面试题的答案并不能保证百分百正确。也就是说各位朋友辛辛苦苦花了很多时间准备…

《程序员的自我修养》阅读笔记

文章目录【第2部分】静态链接1 编译过程2 编辑器的工作流程3 链接——模块的拼接4 目标文件目标文件中的段&#xff08;section&#xff09;ELF文件结构5 静态链接1 空间与地址分配2 符号解析与重定位【第3部分】装载与动态链接1 装载的方式2 进程的启动3 为什么需要动态链接&a…

通俗易懂,十分钟读懂DES,详解DES加密算法原理,DES攻击手段以及3DES原理。Python DES实现源码

文章目录1、什么是DES2、DES的基本概念3、DES的加密流程4、DES算法步骤详解4.1 初始置换(Initial Permutation&#xff0c;IP置换)4.2 加密轮次4.3 F轮函数4.3.1 拓展R到48位4.3.2 子密钥K的生成4.3.3 当前轮次的子密钥与拓展的48位R进行异或运算4.3.4 S盒替换&#xff08;Subs…

学习 create-vite 源码后,感觉真不一样

前言 已经学习了一段时间的源码了&#xff0c;在写源码 demo 小例子的时候都是使用 react 项目作为模板&#xff0c;而我的 react 项目正好是由create-vite来创建的&#xff0c;因此&#xff0c;今天来学习一下关于create-vite的源码。话不多说&#xff0c;咱们直接开始学习。…

【深度学习】什么是线性回归逻辑回归单层神经元的缺陷

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录逻辑回归&线性回归单层神经元的缺陷单层神经元的缺陷逻辑回归&线性回归 线性回归预测的是一个连续值&#xff0c; 逻辑回归给出的”是”和“否”的回答. 等…

MySQL事务与索引

MySQL事务与索引 一、事务 1、事务简介 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。事务处理可以用来维护数据库的完整性&#xff0c;保证成批的 SQL 语句要么全部执行&#xff0c;要么全部不执行。事务用来管理 insert,update,delete 语句 事务特性…

SQL性能优化的47个小技巧,果断收藏!

1、先了解MySQL的执行过程 了解了MySQL的执行过程&#xff0c;我们才知道如何进行sql优化。 客户端发送一条查询语句到服务器&#xff1b; 服务器先查询缓存&#xff0c;如果命中缓存&#xff0c;则立即返回存储在缓存中的数据&#xff1b; 未命中缓存后&#xff0c;MySQL通…

【编程入门】应用市场(go语言版)

背景 前面已输出多个系列&#xff1a; 《十余种编程语言做个计算器》 《十余种编程语言写2048小游戏》 《17种编程语言10种排序算法》 《十余种编程语言写博客系统》 《十余种编程语言写云笔记》 《N种编程语言做个记事本》 目标 为编程初学者打造入门学习项目&#xff0c;使…

qt源码--信号槽

本篇主要从Qt信号槽的连接、断开、调用、对象释放等方面展开&#xff1b; 1.信号建立连接过程 connect有多个重载函数&#xff0c;主要是为了方便使用者&#xff0c;比较常用的有2种方式&#xff1a; a. QObject::connect(&timer, &QTimer::timeout, &loop, &am…

一步步教你电脑变成服务器,tomcat的花生壳设置(原创)

1&#xff0c;首先你去https://console.oray.com/这网站注册个帐号&#xff0c;如果注册成功它会送你一个免费域名&#xff0c;当然不记得也没关系&#xff0c;你记住你注册的 帐号跟密码&#xff0c;然后下载它的软件&#xff08;花生壳动态域名6.0正式版&#xff09;有xp跟li…

19_FreeRTOS软件定时器

目录 软件定时器介绍 FreeRTOS软件定时器特点 软件定时器的命令队列 软件定时器的相关配置 单次定时器和周期定时器 软件定时器结构体成员 FreeRTOS软件定时器相关API函数 实验源码 软件定时器介绍 定时器描述:从指定的时刻开始,经过一个指定时间,然后触发一个超时事件…

操作系统权限提升(十三)之绕过UAC提权-MSF和CS绕过UAC提权

系列文章 操作系统权限提升(十二)之绕过UAC提权-Windows UAC概述 注&#xff1a;阅读本编文章前&#xff0c;请先阅读系列文章&#xff0c;以免造成看不懂的情况&#xff01;&#xff01; MSF和CS绕过UAC提权 CS绕过UAC提权 拿到一个普通管理员的SHELL,在CS中没有*号代表有…