数据结构(Java):力扣 二叉树面试OJ题(二)【进阶】

目录

💎 1、题一:二叉树的层序遍历

🌟 1.1 思路1(递归求解) 

🌟 1.1.1 思路1代码

🔆 1.2 思路2(队列求解)

🔆 1.2.1 思路2代码 

 💎 2、题二:判断是否为完全二叉树

🌟 2.1 思路分析

  🌟 2.2 代码

💎  3、题三:求二叉树中节点的最近公共祖先 

🌟 3.1 思路分析

 🌟 3.2 代码

💎  4、题四:根据二叉树创建字符串

🌟 4.1 思路分析

 🌟 4.2 代码

💎  5、题五:二叉树前序遍历递归实现与非递归实现

🌟 5.1 递归实现->思路分析

 🌟 5.1.1 递归实现->代码

🔆 5.2 非递归实现->思路分析

​编辑 🔆 5.2.1 非递归实现->代码 

💎  6、题六:二叉树中序遍历递归实现与非递归实现

🌟 6.1 递归实现->代码

🔆 6.2 非递归实现->代码

 💎  7、题七:二叉树后序遍历递归实现与非递归实现

🌟 7.1 递归实现->代码

🔆 7.2 非递归实现->思路分析

 🔆 7.2.1 非递归实现->代码 


💎 1、题一:二叉树的层序遍历

. - 力扣(LeetCode)

层序遍历, 即从上到下,从左到右,一层一层的将数据遍历一遍。 

🌟 1.1 思路1(递归求解) 

  1. 首先,根据上篇求树高度的方法,求出二叉树的高度。接着,实例化出高度个一维顺序表添加到二维顺序表中。
  2. 记录好每层数据的层数,根据层数并按顺序来将来将数据添加到二维顺序表的第几行中(记录层数来放入数据,是解题关键点!!!)。
  3. 默认根节点是第0层,与顺序表下标相对应。
  4. 这里以前序遍历的思想递归,添加各层数据。

🌟 1.1.1 思路1代码

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> listVal = new ArrayList<>();if(root == null) {//注意:若根节点为空,要返回空的顺序表return listVal;};int height = treeHeight(root);for(int i = 0; i < height; i++) {List<Integer> list = new ArrayList<>();listVal.add(list);}//根节点的层数默认为0addNode(root,0,listVal);return listVal;}//求树高度public int treeHeight(TreeNode root) {if(root == null) return 0;return Math.max(treeHeight(root.left),treeHeight(root.right)) + 1;}public void addNode(TreeNode root,int level,List<List<Integer>> listVal) {if(root == null) {return;}//以前序遍历的思想,根据层数来将数据添加到该行的顺序表中listVal.get(level).add(root.val);addNode(root.left,level+1,listVal);addNode(root.right,level+1,listVal);} 
}


🔆 1.2 思路2(队列求解)

  1. 首先创建一个队列,将根节点放入队列当中
  2. 每次循环前记录队列中元素个数size,依次出队size个元素,每次出队的元素(节点)都要判断其左右子树是否为空,若不为空则添加到队列中
  3. 将每次出队的元素的val值添加到一维顺序表中,size个元素全部出队完后,将这个一维顺序表添加到二维顺序表中,也就是说,每size个出队的元素都是同一层的节点
  4. 循环以上过程,直至元素全部添加至二维顺序表中(队列为空

🔆 1.2.1 思路2代码 

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> listVal = new ArrayList<>();if (root == null) {//注意:若根节点为空,要返回空的顺序表return listVal; }Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);//队列空时,说明节点已全部添加到二维顺序表中while (!queue.isEmpty()) {int size = queue.size();//存储每一层节点的顺序表List<Integer> list = new ArrayList<>();//将队列中的size个元素依次出队,//并判断其左右子树是否为空,若不为空则添加到队列中while (size != 0) {TreeNode out = queue.poll();list.add(out.val);if (out.left != null) {queue.offer(out.left);}if (out.right != null) {queue.offer(out.right);}size--;}//将每一层的一维顺序表添加到二维顺序表中listVal.add(list);}return listVal;}
}

 💎 2、题二:判断是否为完全二叉树

 本题无链接,

题目即:给出一棵树的根节点,判断是否为完全二叉树。

🌟 2.1 思路分析

这题的解题思路和上一题队列求解差不多,都是借助队列这一数据结构:

  1. 首先,创建队列,放入根节点。
  2. 将一个元素出队,cur接收出队元素,判断cur是否为空,若cur不为空,则将其左右孩子放入队列中(若左右子树为null,也要将null入队),循环这一过程。
  3. 当cur为null时结束循环(出队的是null,cur接收,此时cur为null),此时,只要判断队列中的剩余元素是否存在非null元素:若剩余元素全为null则说明该树为完全二叉树;若剩余元素存在非null元素则说明该树不为完全二叉树。

  🌟 2.2 代码

boolean isCompleteTree(TreeNode root) {if(root == null) {return true;}//创建队列 添加根节点Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);//当cur不为空时,添加其左右孩子TreeNode cur = root;while (cur != null) {cur = queue.poll();if (cur != null) {queue.offer(cur.left);queue.offer(cur.right);}}//cur为空时,判断队列中是否有非空元素//若剩余元素全为null则说明该树为完全二叉树;// 若剩余元素存在非null元素则说明该树不为完全二叉树。boolean flg = false;while (!queue.isEmpty()) {TreeNode cur2 = queue.poll();if (cur2 != null) {flg = true;}}if (flg == true) {return false;}else {return true;}}

💎  3、题三:求二叉树中节点的最近公共祖先 

. - 力扣(LeetCode)

🌟 3.1 思路分析

  • ①:当p、q在根节点的左右子树上时,祖先就是这个根节点
  • ②:当p、q都在根节点的右子树上时,由于节点的祖先可以是它自己,所以祖先就是p或q本身
  • ③:当p、q都在根节点的左子树上时,由于节点的祖先可以是它自己,所以祖先就是p或q本身
  • 以前序遍历思想递归,若遇见p、q节点便返回
  • 若左右子树都有返回值,说明祖先就是这个根节点;(对于第一层的根节点)若只有左子树有返回值,说明p、q均在左子树上,返回的节点就是最近祖先;(对于第一层的根节点)若只有右子树有返回值,说明p、q均在右子树上,返回的节点就是最近祖先。

 🌟 3.2 代码

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {return findNode( root,  p,  q);}public TreeNode findNode(TreeNode root, TreeNode p, TreeNode q) {if(root == null) {return null;}//先判断根节点是否为p、q节点if(root.val == p.val || root.val == q.val) {return root;}//查找左右子树TreeNode leftNode = findNode(root.left,p,q);TreeNode rightNode = findNode(root.right,p,q);   //若左右子树都有返回值,说明祖先就是这个根节点    if(leftNode != null && rightNode != null) {return root;}//在左树上找到了if(leftNode != null && rightNode == null) {return leftNode;}//在右树上找到了if(rightNode != null && leftNode == null) {return rightNode;}return null;}
}

💎  4、题四:根据二叉树创建字符串

. - 力扣(LeetCode)

🌟 4.1 思路分析

  1. 借助StringBuffer拼接字符串,最后返回字符串
  2. 以前序遍历思想递归
  3. 拼接当前根节点,判断根节点的左孩子是否为空,若左孩子不为空则拼接"(",并递归左子树;若左孩子为空且右孩子为空,则直接返回即可;若左孩子为空但右孩子不为空,注意!!!此时应该拼接"()",继续递归右子树。
  4. 若右孩子为空,则直接返回;若右孩子不为空,则拼接"("并递归右子树。
  5. 在根节点的左右子树完成即递归回退后拼接相应的")"
  6. 调用toString方法返回字符串

 🌟 4.2 代码

 class Solution {StringBuilder stringBuilder = new StringBuilder();public String tree2str(TreeNode root) {tree2strChild(root);return stringBuilder.toString();}public void tree2strChild(TreeNode root) {if(root == null) {return ;}stringBuilder.append(root.val);if(root.left != null) {//左子树不为空,则必然添加"("stringBuilder.append("(");//递归左子树tree2strChild(root.left);//该节点左子树完,则拼接")"stringBuilder.append(")");}else {//左子树为空,且右子树为空,直接返回if(root.right == null) {return;}else {//左子树为空,但右子树不为空,需拼接"()"stringBuilder.append("()");}}//若右孩子为空,则直接返回;若右孩子不为空,则拼接"("并递归右子树if (root.right != null) {stringBuilder.append("(");tree2str(root.right);stringBuilder.append(")");}else {return;}}
}

💎  5、题五:二叉树前序遍历递归实现与非递归实现

 . - 力扣(LeetCode)

🌟 5.1 递归实现->思路分析

递归实现前序遍历的思想很简单:就是先将根节点的数据放入顺序表中,再将左子树的数据放入顺序表中, 再将右子树的数据放入顺序表中。

 🌟 5.1.1 递归实现->代码

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();if(root == null) {return list;}list.add(root.val);List<Integer> leftList = preorderTraversal(root.left);list.addAll(leftList);List<Integer> rightList = preorderTraversal(root.right);list.addAll(rightList);return list;}
}

🔆 5.2 非递归实现->思路分析

 非递归实现遍历,我们需要借助一种数据结构--->

注意:本题要求将数值放入顺序表中,返回顺序表。故这里访问根节点时,对根节点的操作是将根节点的val值添加到顺序表中。 

  1. 创建栈和顺序表,将根节点赋值给cur
  2. 将cur入栈并将cur的val值添加到顺序表中,cur更新为cur的left,接着将cur入栈并将cur的val值添加到顺序表中。循环操作,直到cur为空
  3. 此时cur为空,pop弹出栈顶元素赋给top,将cur更新为top.right;若top.right为空,即更新的cur为空,则继续弹出栈顶元素(top接收),直至cur不为空。
  4. 此时cur不为空,循环2、3步骤,直至栈中元素为空,说明树中元素已按照前序遍历的方式全部添加到了顺序表中。

 🔆 5.2.1 非递归实现->代码 

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();Stack<TreeNode> stack = new Stack<>();TreeNode cur = root;//注意这里的循环条件//因为后续cur为空时要弹出栈顶元素,故栈不能为空//且一开始时栈为空,故cur不为空就可进入循环//当栈空且cur为空,说明前序遍历已完成while (cur != null || !stack.isEmpty()) {//cur不为空就要进栈,并添加进顺序表//cur = cur.leftwhile (cur != null) {stack.push(cur);list.add(cur.val);cur = cur.left;}//当cur为空时,弹出栈顶元素(top),赋给cur其右子树//若cur还是为空(top.right为空),循环过来继续弹出元素,并赋给cur新的top.rightTreeNode top = stack.pop();cur = top.right;}return list;}
}

💎  6、题六:二叉树中序遍历递归实现与非递归实现

. - 力扣(LeetCode)

中序遍历的实现,不管是在递归实现上还是在非递归实现上,和前序遍历的思想都是相同的,只是访问根节点的时机有所不同。

🌟 6.1 递归实现->代码

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>(); if(root == null) {return list;}List<Integer> listLeft = inorderTraversal(root.left);list.addAll(listLeft);list.add(root.val);List<Integer> listRight = inorderTraversal(root.right);list.addAll(listRight);return list;}
}

🔆 6.2 非递归实现->代码

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();Stack<TreeNode> stack = new Stack<>();TreeNode cur = root;//注意这里的循环条件//因为后续cur为空时要弹出栈顶元素,故栈不能为空//且一开始时栈为空,故cur不为空就可进入循环//当栈空且cur为空,说明前序遍历已完成while (cur != null || !stack.isEmpty()) {//cur走左子树while (cur != null) {stack.push(cur);cur = cur.left;}//当cur为空时,弹出栈顶元素(top),添加进顺序表,赋给cur其右子树//若cur还是为空(top.right为空),循环过来继续弹出元素,并赋给cur新的top.rightTreeNode top = stack.pop();list.add(top.val);cur = top.right;}return list;}
}

 💎  7、题七:二叉树后序遍历递归实现与非递归实现

. - 力扣(LeetCode)

 后序遍历的实现,在递归上,与前序、中序遍历的思想是相同的,在此不再赘述。

而在非递归的实现上,后序遍历需要额外注意几点。

🌟 7.1 递归实现->代码

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();if(root == null) {return list;}List<Integer> list1 = postorderTraversal(root.left);list.addAll(list1);List<Integer> list2 = postorderTraversal(root.right);list.addAll(list2);list.add(root.val);return list;}
}

🔆 7.2 非递归实现->思路分析

 后序遍历在非递归的实现上,需要额外注意几点:

  1. 当cur为空时,不可直接将栈顶元素弹出并添加进顺序表(或打印,只是访问根节点时的操作不同)
  2. 因为栈顶元素即根节点,后序遍历,需要判断栈顶元素的右孩子是否为空,若为空,才可弹出栈顶元素并打印;若右孩子不为空,需要先对右子树中的元素进行入栈和打印操作
  3. 而当栈顶元素的右孩子不为空时,我们又需要额外注意一点!!!当栈顶元素的右孩子不为空时,那就说明这个栈顶元素将永远不能出栈,会造成死循环!!!我们需要记录进过栈的元素,避免死循环的出现!!! 

发生死循环过程如下图:

 🔆 7.2.1 非递归实现->代码 

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();Stack<TreeNode> stack = new Stack<>();TreeNode cur = root;//prev指向被打印过的节点TreeNode prev = null;//注意这里的循环条件//因为后续cur为空时要弹出栈顶元素,故栈不能为空//且一开始时栈为空,故cur不为空就可进入循环//当栈空且cur为空,说明前序遍历已完成while (cur != null || !stack.isEmpty()) {//cur走左子树while (cur != null) {stack.push(cur);cur = cur.left;}//当cur为空时,不可直接将栈顶元素弹出和添加进顺序表//要判断栈顶元素(根节点)是否有右孩子//若右孩子为空可以弹出和添加//若右孩子不为空,需要先将右子树的元素入栈并添加TreeNode top = stack.peek();//当栈顶元素的右孩子入过栈时,此时栈顶元素可以弹出并添加进顺序表if(top.right == null || top.right == prev) {stack.pop();list.add(top.val);prev = top;}else {cur = top.right;}}return list;}
}

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

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

相关文章

MySQL1

新建产品库mydb6_product: mysql> create database mydb6_product; mysql> use mydb6_product; 建立employees表&#xff1a; mysql> create table employees(id int primary key, name varchar(50) not null, age int, gender varchar(10) not null default unknow…

【chatgpt】通过游戏理解强化学习概念策略policy,动作action和状态state

可以将策略&#xff08;policy&#xff09;类比为一个游戏中的决策指南。假设你正在玩一个游戏&#xff0c;在每个游戏场景&#xff08;状态&#xff09;下&#xff0c;你需要决定下一步应该做什么&#xff08;动作&#xff09;。策略就是告诉你在每个场景下应该做什么的指南。…

查询Mysql数据库所有数据库所占磁盘空间大小

查询Mysql数据库所有数据库所占磁盘空间大小&#xff1a; select TABLE_SCHEMA, concat(truncate(sum(data_length)/1024/1024,2), MB) as data_size, concat(truncate(sum(index_length)/1024/1024,2),MB) as index_size from information_schema.tables group by TABLE_SCHE…

无需业务改造,一套数据库满足 OLTP 和 OLAP,GaiaDB 发布并行查询能力

在企业中通常存在两类数据处理场景&#xff0c;一类是在线事务处理场景&#xff08;OLTP&#xff09;&#xff0c;例如交易系统&#xff0c;另一类是在线分析处理场景&#xff08;OLAP&#xff09;&#xff0c;例如业务报表。 OLTP 数据库擅长处理数据的增、删、改&#xff0c…

首个WebAgent在线评测框架和流程数据管理平台来了,GPT-4、Qwen登顶闭源和开源榜首!

在当今科技迅速发展的时代&#xff0c;大型语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;正以前所未有的速度改变着我们与数字世界的互动方式。基于LLM的智能代理&#xff08;LLM Agent&#xff09;&#xff0c;从简单的信息搜索到复杂的网页操作&…

【Spring Cloud】掌握Gateway核心技术,实现高效路由与转发

目录 前言示例创建一个服务提供者创建网关 创建common子项目 前言 Spring Cloud Gateway 是一个基于 Spring Boot 的非阻塞 API 网关服务&#xff0c;它提供了动态路由、请求断言、过滤器等功能。 以下是关于 Spring Cloud Gateway 的示例&#xff1a; 示例 创建一个服务提…

ECMP等价多路由机制,大模型训练负载均衡流量极化冲突原因,万卡(大规模)集群语言模型(LLM)训练流量拥塞特点

大规模集群&#xff0c;大语言模型(LLM)训练流量特点&#xff0c;ECMP&#xff08;Equal-Cost Multi-Path Routing&#xff09;流量极化拥塞原因。 视频分享在这&#xff1a; 2.1 ECMP等价多路由&#xff0c;大模型训练流量特点&#xff0c;拥塞冲突极化产生原因_哔哩哔哩_bi…

tmux【避免意外关机导致中断服务器中运行的程序】

文章目录 概要1.创建一个新的 tmux 会话2.退出 tmux 会话3.进入 tmux 会话4.终止一个 tmux 会话 概要 #创建一个新的 tmux 会话 tmux new -s my-session #退出 tmux 会话Ctrl-b d #进入 tmux 会话 tmux ls tmux attach -t my-session #终止一个 tmux 会话 tmux kill-session -…

ubuntu如何彻底卸载android studio?

最新版的ubuntu已经使用snap进行软件管理了&#xff0c;我用snap-store安装android studio以后&#xff0c;在安装plugin的时候强制退出后&#xff0c;直接再也进不去了&#xff0c;启动就报错。 先后进行了如下操作依然不行&#xff1a; 1 重装snap-store和android studio都…

【Docker】Docker-harbor私有仓库部署与管理

目录 一.Harbor 概述 1.什么是Harbor 2.Harbor的特性 3.Harbor的构成 二.Harbor 部署 1.部署 Docker-Compose 服务 2.部署 Harbor 服务 3.启动 Harbor 4.创建新项目 5.创建用户 6.本地上传镜像 7.从Harbor下载镜像 三.镜像同步 1.定时拉取 2.主动推送 四.管理 …

阿里云开源 Qwen2-Audio 音频聊天和预训练大型音频语言模型

Qwen2-Audio由阿里巴巴集团Qwen团队开发&#xff0c;它能够接受各种音频信号输入&#xff0c;对语音指令进行音频分析或直接文本回复。与以往复杂的层次标签不同&#xff0c;Qwen2-Audio通过使用自然语言提示简化了预训练过程&#xff0c;并扩大了数据量。 喜好儿网 Qwen2-Au…

某国有酒店管理公司薪酬激励项目成功案例纪实

——激发团队整体积极性&#xff0c;激励骨干员工&#xff0c;实现多劳多得、降本增效 【客户行业】酒店&#xff1b;服务业&#xff1b; 【问题类型】激励机制 【客户背景】 南方某酒店管理公司隶属于某市政府&#xff0c;是一家五星级高级商务会议型酒店&#xff0c;该酒…

SQLite 事务

SQLite 事务 SQLite 是一种轻量级的数据库管理系统,广泛用于各种应用程序中,特别是在移动设备和嵌入式系统中。它支持标准的 SQL 语法,包括事务处理。事务是数据库管理系统中的一个重要概念,它允许将一系列操作作为一个单独的工作单元来处理,以确保数据库的一致性和可靠性…

OpenSearch IoT 设备日志分析

在物联网(IoT)时代,设备日志分析对于理解设备行为、优化性能和提高用户体验至关重要。本文将介绍10个使用OpenSearch进行IoT设备日志分析的实用案例,这些案例涵盖了从基本统计到高级分析的多个方面。 背景 假设我们有一个名为 ​​pro-iot-2024-07-16​​ 的OpenSearch索…

Anylogic中Excel 文件(Excel file)的使用

Excel 文件连接工具提供了在 AnyLogic 模型中轻松访问 MS Excel&#xff08;.xls, .xlsx&#xff09;文件的平台无关方式。使用此对象&#xff0c;您可以&#xff1a; 读取 Excel 文件并浏览其内容&#xff0c; 演示模型&#xff1a; 读取和写入 Excel 文件 在 AnyLogic Cloud…

Python中Selenium 和 keyboard 库的使用

文章目录 一、Selenium基本使用2.等待元素加载常用操作 keyboard基本使用与 Selenium 联合使用 一、Selenium Selenium 是一个用于浏览器自动化的工具。它可以模拟用户与网页的交互&#xff0c;如点击按钮、填写表单、导航页面等。Selenium 支持多种编程语言&#xff0c;包括 …

python + Pytest + requests 的接口自动化步骤

pythonpytestrequestallureyaml接口自动化测试项目实战 开发环境准备 1. jdk 下载 Java官网下载地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 安装&#xff1a; https://blog.csdn.net/VA_AV/article/details/138…

1.厦门面试

1.Vue的生命周期阶段 vue生命周期分为四个阶段 第一阶段&#xff08;创建阶段&#xff09;&#xff1a;beforeCreate&#xff0c;created 第二阶段&#xff08;挂载阶段&#xff09;&#xff1a;beforeMount&#xff08;render&#xff09;&#xff0c;mounted 第三阶段&#…

Mongodb文本索引

学习mongodb&#xff0c;体会mongodb的每一个使用细节&#xff0c;欢迎阅读威赞的文章。这是威赞发布的第94篇mongodb技术文章&#xff0c;欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题&#xff0c;欢迎在文章下面点个赞&#xff0c;或者关…

使用SpringBoot集成Swagger3.0实现在线接口文档功能

概述 Swagger 3.0 是一个开源的框架&#xff0c;用于设计、构建和文档化 RESTful API。它允许开发者定义 API 规范&#xff0c;包括请求、响应、端点等信息&#xff0c;并生成交互式 API 文档。Knife4j 则是 Swagger 的一个增强版本&#xff0c;提供了更美观和功能丰富的界面。…