算法通关村第八关——轻松搞定二叉树的深度和高度问题

news/2024/11/20 13:34:42/

1.基础知识

二叉树节点的高度:指从当前节点到叶子节点的最长简单路径边的条数

二叉树节点的深度:指从根节点到当前节点的最长简单路径边的条数

二叉树的深度和高度问题,递归思想的运用很是普遍,有的问题层序遍历也可以解决。

在这里插入图片描述

2.最大深度问题

力扣104题,给定一个二叉树,找出最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明:叶子节点是指没有子节点的节点。

递归的三步走:输入输出参数、递归终止条件、完整的递归逻辑。

在这里插入图片描述

分析:对于rootNode(7),最大深度很明显是左右子节点深度+1,当然,左右子节点存在为空的情况,但只要有一个不为空,树的最大高度就是1+1=2。再增加几个节点:

在这里插入图片描述

对于node(3),最大深度仍然是左右子节点深度+1,左右子节点只要有一个不为空,node(3)的最大高度是1+1=2。而对于rootNode(7),则是左右子树中深度最大的一个+1,于是对于rootNode(7)的判断逻辑用代码表示就是:

let leftDepth = getDepth(root.left);
let rightDepth = getDepth(root.right);
let maxDepth = Math.max(leftDepth, rightDepth) + 1;

递归终止的条件就是root === null然后返回0就行。输入参数就是子树的根节点root,返回值为当前root所在子树的最大高度。

function maxDepth(root) {if (root === null) {return 0;}// 得到根节点左右子树的最大深度let leftDepth = maxDepth(root.left);let rightDepth = maxDepth(root.right);return Math.max(leftDepth, rightDepth) + 1;
}

仔细观察可以发现,先拿到左右子树的结果,再计算根节点的深度,这与后序遍历本质一样。

层序遍历也可以得到最大深度,方法就是每遍历一层,设置的记录层数的变量+1即可。代码如下:

function maxDepth(root) {if (root === null) {return 0;}let maxDepth = 0;const treeQueue = [root];while (treeQueue.length !== 0) {// lenOfTreeQueue表示每一层的元素数lenOfTreeQueue = treeQueue.length;// lenOfTreeQueue=0表示一层访问完了while (lenOfTreeQueue > 0) {  let treeNode = treeQueue.pop();if (treeNode.left !== null) {treeQueue.push(treeNode.left);}if (treeNode.right !== null) {treeQueue.push(treeNode.left);}lenOfTreeQueue--;}maxDepth++;}return maxDepth;
}

3 判断平衡二叉树

力扣110题,给定一个二叉树,判断它是否是高度平衡的二叉树。本题中高度平衡二叉树定义为:一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。

关于根节点的深度究竟是1 还是 0,不同的地方有不一样的标准,leetcode的题目中都是以根节点深度是1,我们以leetcode为准。

在这里插入图片描述

分析:对于rootNode(7),左右孩子如果只有一个,高度差就是1;如果左右孩子都有或者都没有,则高度差为0。再增加一层。

在这里插入图片描述

对于rootNode(7),需要知道它的左右子树的最大高度差是否 < 2

  • root节点的左右子树高度差 < 2,就返回左右子树最大高度+1
  • root节点左右子树的高度差 >= 2,就返回-1,表示此子树不是平衡树。

用代码来表示就是:

let leftHeight = getHeight(root.left);
let rightHeight = getHeight(root.right);
return Math.abs(leftHeight - rightHeight) < 2 ? Math.max(leftHeight, rightHeight) + 1 : -1;

完整代码如下:

function isBalanced(root) {if (nodeHeight(root) >= 0) {return true;} else return false;function nodeHeight(root) {if (root === null) {return false;}let leftNodeHeight = nodeHeight(root.left);let rightNodeHeight = nodeHeight(root.right);// 若当前节点左右子树的高度差<2,返回当前节点的左右子树最大高度+1// 若当前节点左右子树的高度差>=2,返回-1if (leftNodeHeight === -1 || rightNodeHeight === -1 || Math.abs(leftNodeHeight - rightNodeHeight) >= 2) {return -1;} else {return Math.max(leftNodeHeight, rightNodeHeight) + 1;}}
}

4.最小深度问题

力扣111题,给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量,例如下面的例子返回结果为2。说明:叶子节点是指没有子节点的节点。

在这里插入图片描述

最小深度的一层必须是要到叶子节点

分析终止条件:

  • 如果左子树为空,右子树不为空,说明最小深度是1+右子树的深度
  • 相反,如果右子树为空,左子树不为空,最小深度就是1+左子树的深度
  • 如果左右子树都不为空,返回左右子树深度中最小值+1.

代码如下:

function minDepth(root) {if (root === null) {return 0;}// 终止条件有三种// 1.当前节点的左右子节点都为空,说明到达了叶子节点,leftDepth和rightDepth为0// 2.左右子树其中一个为空,leftDepth和rightDepth其中一个为0,就返回比较大的那个子树深度let leftDepth = minDepth(root.left);let rightDepth = minDepth(root.right);if {root.left === null || root.right === null} {return leftDepth + rightDepth + 1;}// 3.最后一种情况,也就是左右孩子都不为空,返回左右子树最小深度+1return Math.min(leftDepth, rightDepth) + 1;
}

这道题同样也能用层序遍历来解决。遍历时,第一次遇到叶子就直接返回其所在层次即可:

function minDepth(root) {if (root === null) {return 0;}let minDepth = 0;const treeQueue = [root];while (treeQueue.length !== 0) {lenOfTreeQueue = treeQueue.length;minDepth++;let treeNode = treeQueue.pop();// 如果左右子节点均为空,说明是叶子节点,直接返回if (treeNode.left === null && treeNode.right === null) {return minDepth;}if (treeNode.left !== null) {treeQueue.push(treeNode.left);}if (treeNode.right !== null) {treeQueue.push(treeNode.left);}}

5.N叉树的最大深度

力扣559题,给定一个 N 叉树,找到其最大深度。最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔,比如:

示例1:
输入:root = [1,null,3,2,4,null,5,6]
输出:3
示例2:
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:5

分析:N叉树与二叉树不同之处就在于N叉树节点比较多,root的子节点为N个,也就是N个子树。记N个子树的最大深度中的最大值为maxChildDepth,那么该N叉树的最大深度为maxChildDepth + 1

var maxDepth = function(root) {	if (root === null) {return 0;} else if (root.children === null) {return 1;}let maxChildDepth = 0;const children = root.children;for(const child of children) {// 记录当前子树的最大深度const childDepth = maxDepth(child);// 将当前子树的最大深度与记录的最大子树深度进行比较maxChildDepth = Math.max(maxChildDepth, childDepth);}return maxChildDepth + 1; 
}

用层次遍历来解决的话,我们每次从队列里拿出当前层的所有节点,这样下一次遍历的就是当前层的所有子节点,以此类推。设置一个记录遍历层数的变量。

function maxDepth(root) {if (root === null) {return 0;} else if (root.children === null) {return 1;}const treeQueue = [root];let maxDepth = 0;while (treeQueue.length !== 0) {// 记录每层所有节点数let lenOfTreeQueue = treeQueue.length;while (lenOfTreeQueue > 0) {const node = treeQueue.shift();const children = node.children;for (const child of children) {treeQueue.push(child);}lenOfTreeQueue--;}maxDepth++;}return maxDepth
}

总结

牢记递归三步走:

  1. 从局部到整体递推
  2. 分情况讨论,明确递归终止条件
  3. 得出完整的递归逻辑

如果想验证的话,就从整体到局部画图推演。


http://www.ppmy.cn/news/1044183.html

相关文章

SpringBoot整合RabbitMQ,笔记整理

1创建生产者工程springboot-rabbitmq-produce 2.修改pom.xml文件 <!--父工程--> <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.0</version><r…

第三章MyBatisCRUD

新增 map集合实现新增 创建测试用例加入如下代码 Testpublic void mapSave() {SqlSession sqlSession SqlSessionUtil.createSqlSession();Map<String, Object> mapnew HashMap<>();map.put("carNum","999");map.put("brand",&qu…

【数据结构OJ题】用栈实现队列

原题链接&#xff1a;https://leetcode.cn/problems/implement-queue-using-stacks/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 用两个栈实现&#xff0c;一个栈进行入队操作&#xff0c;另一个栈进行出队操作。 出队操作&#xff1a; 当出队的栈…

计组 | 机器周期、平均运算速率、数据传输速率、总线带宽怎么计算?

目录 一、计算公式 二、练习题 1.总线带宽 2.机器周期 3.平均运算速度 4.数据传输速率 一、计算公式 总线带宽计算&#xff1a; 总线带宽Dr时钟频率f 数据量D D /&#xff08;时钟周期T/(一个总线周期占用时钟周期的个数)&#xff09; 其中涉及到的单位MHz与 MB/s是怎…

sql:知识点记录一

1.Mysql逻辑架构&#xff1a;连接层、服务层、引擎层、存储层 2.show engines&#xff1a;查看存储引擎 3.Mysql两种存储引擎的区别&#xff1a; 建立索引&#xff1a;比如说用户很喜欢用name去查询表&#xff0c;就可以给数据库的name字段建立索引&#xff0c;提高查询效率&a…

Azure创建可用性集

什么是可用性集 在Azure中&#xff0c;可用性集&#xff08;Availability Set&#xff09;是一种用于提高虚拟机&#xff08;VM&#xff09;可用性和可靠性的功能。它通过将虚拟机分布在不同的物理硬件和故障域中来提供高可用性。每个故障域都是一个独立的电力和网络故障区域&…

ps丢失d3dcompiler_47.dll怎么办,启动无反应,分享三个解决方法

d3dcompiler_47.dll64位是windows系统中重要的dll文件&#xff0c;缺少了它可能会引起部分软件或者游戏不能运行。 如果系统出现“找不到d3dcompiler_47.dll”或“d3dcompiler_47.dll丢失”等错误信息&#xff0c;那么我们就该着手修复它。 先带了解一下d3dcompiler_47.dll是什…

一些常用的CSDN 设置命令、插入目录、改变字体颜色等

文章目录 字体颜色显示调节插入图片大小图片居中 字体颜色显示 字体两边加 调节插入图片大小 注意下边多一个600x600&#xff0c;等号前边有个空格 在这里插入图片描述](https://img-blog.csdnimg.cn/5a0d3d2d37cf481db0e1346432be3da1.png [在这里插入图片描述](https://img-…