剑指Offer面试题:33.二叉树的深度
一、题目一:二叉树的深度
1.1 题目说明
题目一:输入一棵二叉树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。例如下图中的二叉树的深度为4,因为它从根结点到叶结点最长的路径包含4个结点(从根结点1开始,经过结点2和结点5,最终到达叶结点7)。
二叉树的结点定义如下,这里使用C#语言描述:
- public class BinaryTreeNode
- {
- public int Data { get; set; }
- public BinaryTreeNode LeftChild { get; set; }
- public BinaryTreeNode RightChild { get; set; }
- public BinaryTreeNode(int data)
- {
- this.Data = data;
- }
- public BinaryTreeNode(int data, BinaryTreeNode left, BinaryTreeNode right)
- {
- this.Data = data;
- this.LeftChild = left;
- this.RightChild = right;
- }
- }
1.2 解题思路
①如果一棵树只有一个结点,它的深度为1。
②如果根结点只有左子树而没有右子树,那么树的深度应该是其左子树的深度加1;同样如果根结点只有右子树而没有左子树,那么树的深度应该是其右子树的深度加1。
③如果既有右子树又有左子树,那该树的深度就是其左、右子树深度的较大值再加1。
比如在上图的二叉树中,根结点为1的树有左右两个子树,其左右子树的根结点分别为结点2和3。根结点为2的左子树的深度为3,而根结点为3的右子树的深度为2,因此根结点为1的树的深度就是4。
- public static int GetTreeDepth(BinaryTreeNode root)
- {
- if (root == null)
- {
- return ;
- }
- int left = GetTreeDepth(root.LeftChild);
- int right = GetTreeDepth(root.RightChild);
- return left >= right ? left + : right + ;
- }
1.3 单元测试
(1)测试用例
- [TestClass]
- public class TreeDepthTest
- {
- private void SetSubTreeNode(BinaryTreeNode root, BinaryTreeNode lChild, BinaryTreeNode rChild)
- {
- if (root == null)
- {
- return;
- }
- root.LeftChild = lChild;
- root.RightChild = rChild;
- }
- private void ClearUpTreeNode(BinaryTreeNode root)
- {
- if (root != null)
- {
- BinaryTreeNode left = root.LeftChild;
- BinaryTreeNode right = root.RightChild;
- root = null;
- ClearUpTreeNode(left);
- ClearUpTreeNode(right);
- }
- }
- // 1
- // / \
- // 2 3
- // /\ \
- // 4 5 6
- // /
- //
- [TestMethod]
- public void GetDepthTest1()
- {
- BinaryTreeNode node1 = new BinaryTreeNode();
- BinaryTreeNode node2 = new BinaryTreeNode();
- BinaryTreeNode node3 = new BinaryTreeNode();
- BinaryTreeNode node4 = new BinaryTreeNode();
- BinaryTreeNode node5 = new BinaryTreeNode();
- BinaryTreeNode node6 = new BinaryTreeNode();
- BinaryTreeNode node7 = new BinaryTreeNode();
- SetSubTreeNode(node1, node2, node3);
- SetSubTreeNode(node2, node4, node5);
- SetSubTreeNode(node3, null, node6);
- SetSubTreeNode(node5, node7, null);
- int actual = TreeDepthHelper.GetTreeDepth(node1);
- Assert.AreEqual(actual, );
- ClearUpTreeNode(node1);
- }
- // 1
- // /
- // 2
- // /
- // 3
- // /
- // 4
- // /
- //
- [TestMethod]
- public void GetDepthTest2()
- {
- BinaryTreeNode node1 = new BinaryTreeNode();
- BinaryTreeNode node2 = new BinaryTreeNode();
- BinaryTreeNode node3 = new BinaryTreeNode();
- BinaryTreeNode node4 = new BinaryTreeNode();
- BinaryTreeNode node5 = new BinaryTreeNode();
- SetSubTreeNode(node1, node2, null);
- SetSubTreeNode(node2, node3, null);
- SetSubTreeNode(node3, node4, null);
- SetSubTreeNode(node4, node5, null);
- int actual = TreeDepthHelper.GetTreeDepth(node1);
- Assert.AreEqual(actual, );
- ClearUpTreeNode(node1);
- }
- // 1
- // \
- // 2
- // \
- // 3
- // \
- // 4
- // \
- //
- [TestMethod]
- public void GetDepthTest3()
- {
- BinaryTreeNode node1 = new BinaryTreeNode();
- BinaryTreeNode node2 = new BinaryTreeNode();
- BinaryTreeNode node3 = new BinaryTreeNode();
- BinaryTreeNode node4 = new BinaryTreeNode();
- BinaryTreeNode node5 = new BinaryTreeNode();
- SetSubTreeNode(node1, null, node2);
- SetSubTreeNode(node2, null, node3);
- SetSubTreeNode(node3, null, node4);
- SetSubTreeNode(node4, null, node5);
- int actual = TreeDepthHelper.GetTreeDepth(node1);
- Assert.AreEqual(actual, );
- ClearUpTreeNode(node1);
- }
- // 树中只有1个结点
- [TestMethod]
- public void GetDepthTest4()
- {
- BinaryTreeNode node1 = new BinaryTreeNode();
- int actual = TreeDepthHelper.GetTreeDepth(node1);
- Assert.AreEqual(actual, );
- ClearUpTreeNode(node1);
- }
- // 树中没有结点
- [TestMethod]
- public void GetDepthTest5()
- {
- int actual = TreeDepthHelper.GetTreeDepth(null);
- Assert.AreEqual(actual, );
- }
- }
(2)测试结果
①测试通过情况
②代码覆盖率
二、题目二:判断二叉树是否是平衡二叉树
2.1 题目说明
题目二:输入一棵二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。例如,下图中的二叉树就是一棵平衡二叉树。
2.2 解题思路
(1)需要重复遍历节点多次的解法
有了求二叉树的深度的经验之后再解决这个问题,我们很容易就能想到一个思路:在遍历树的每个结点的时候,调用函数TreeDepth得到它的左右子树的深度。如果每个结点的左右子树的深度相差都不超过1,按照定义它就是一棵平衡的二叉树。
- public static bool IsBalancedBinaryTree(BinaryTreeNode root)
- {
- if (root == null)
- {
- return true;
- }
- int left = GetTreeDepth(root.LeftChild);
- int right = GetTreeDepth(root.RightChild);
- int diff = left - right;
- if (diff > || diff < -)
- {
- return false;
- }
- return IsBalancedBinaryTree(root.LeftChild) && IsBalancedBinaryTree(root.RightChild);
- }
上面的代码固然简洁,但我们也要注意到由于一个结点会被重复遍历多次,这种思路的时间效率不高。例如在IsBalancedBinaryTree方法中输入上图中的二叉树,我们将首先判断根结点(结点1)是不是平衡的。此时我们往函数TreeDepth输入左子树的根结点(结点2)时,需要遍历结点4、5、7。接下来判断以结点2为根结点的子树是不是平衡树的时候,仍然会遍历结点4、5、7。毫无疑问,重复遍历同一个结点会影响性能。
(2)每个节点只需遍历一次的解法
换个角度来思考,如果我们用后序遍历的方式遍历二叉树的每一个结点,在遍历到一个结点之前我们就已经遍历了它的左右子树。只要在遍历每个结点的时候记录它的深度(某一结点的深度等于它到叶节点的路径的长度),我们就可以一边遍历一边判断每个结点是不是平衡的。
- public static bool IsBalancedBinaryTree(BinaryTreeNode root)
- {
- int depth = ;
- return IsBalancedBinaryTreeCore(root, ref depth);
- }
- private static bool IsBalancedBinaryTreeCore(BinaryTreeNode root, ref int depth)
- {
- if (root == null)
- {
- depth = ;
- return true;
- }
- int left = ;
- int right = ;
- if (IsBalancedBinaryTreeCore(root.LeftChild, ref left) && IsBalancedBinaryTreeCore(root.RightChild, ref right))
- {
- int diff = left - right;
- if (diff >= - && diff <= )
- {
- depth = left >= right ? left + : right + ;
- return true;
- }
- }
- return false;
- }
在上面的代码中,我们用后序遍历的方式遍历整棵二叉树。在遍历某结点的左右子结点之后,我们可以根据它的左右子结点的深度判断它是不是平衡的,并得到当前结点的深度。当最后遍历到树的根结点的时候,也就判断了整棵二叉树是不是平衡二叉树。
2.3 单元测试
此方法的单元测试和第一种方法的一致,这里就不再贴出。需要注意的就是在针对二叉树的测试用例中,需要考虑两种:功能测试(平衡的二叉树,不是平衡的二叉树,二叉树中所有结点都没有左/右子树)。特殊输入测试(二叉树中只有一个结点,二叉树的头结点为NULL指针)。
剑指Offer面试题:33.二叉树的深度的更多相关文章
- 剑指Offer - 九度1350 - 二叉树的深度
剑指Offer - 九度1350 - 二叉树的深度2013-11-23 00:54 题目描述: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的 ...
- 剑指offer【08】- 二叉树的深度(java)
题目:二叉树的深度 考点:知识迁移能力 题目描述:输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 牛客网上的剑指offer题, ...
- 【剑指offer】55 - I. 二叉树的深度
剑指 Offer 55 - I. 二叉树的深度 知识点:二叉树,递归 题目描述 输入一棵二叉树的根节点,求该树的深度.从根节点到叶节点依次经过的节点(含根.叶节点)形成树的一条路径,最长路径的长度为树 ...
- 剑指Offer:面试题25——二叉树中和为某一值的路径(java实现)
问题描述: 输入一棵二叉树和一个整数,打印出二叉树中结点指的和为输入整数的所有路径.从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.二叉树结点的定义如下: public class Tree ...
- 剑指Offer:面试题19——二叉树的镜像(java实现)
问题描述: 操作给定的二叉树,将其变换为源二叉树的镜像. 二叉树结点定义为: public class TreeNode { int val = 0; TreeNode left = null; Tr ...
- 剑指offer面试题19 二叉树的镜像
题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ ...
- 剑指Offer面试题33(java版):把数组排成最小的数
题目:输入一个正整数数组.把数组里面全部的数字拼接排成一个数,打印能拼接出的全部数字中的一个.比如输入数组{3,32.321}.则打印出这3个数字能排成的最小数字321323. 这个题目最直接的做法应 ...
- 剑指Offer:面试题33——把数组排成最小的数(java实现)(未完待续)
问题描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 思路1: ...
- 剑指offer(38)二叉树的深度
题目描述 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 题目分析 树的深度=左子树的深度和右子树深度中最大者+1 代码 fu ...
- 【剑指Offer】38、二叉树的深度
题目描述: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 解题思路: 本题相对比较简单.根据二叉树深度的定义 ...
随机推荐
- GruntJS学习(转)
GruntJS 是基于JavaScript的命令行构建工具,它可以帮助开发者们自动化重复性的工作.你可以把它看成是JavaScript下的Make或者Ant.它可以完成诸如精简.编译.单元测试.lin ...
- git使用
1.权限校验 首先,您的数据保存在远端服务器一份,服务器需要对您的身份进行识别,一段RAS加密字串, 启动GUI,step1:创建秘钥,generate SSHkey. step2:添加密钥:去你的代 ...
- [spring源码学习]四、IOC源码——普通bean初始化
一.代码例子 此节开始涉及到一个bean具体生成和保存的过程,仅仅涉及到最简单的bean,代码依旧是最简单的 public static void main(String[] args) { Defa ...
- openfl使用64位的ndk时,编译报错的问题!
当使用64位的ndk时,如果使用openfl test android运行android测试,应该会出现 arm-linux-androideabi-g++:找不到这个命令的错误. 原因是,haxel ...
- Sprint2团队贡献分
团队贡献分: 郭志豪:31% http://www.cnblogs.com/gzh13692021053/ 杨子健:22%http://www.cnblogs.com/yzj666/ 谭宇森:23% ...
- iOS automaticallyAdjustsScrollViewInsets
self.automaticallyAdjustsScrollViewInsets = NO; //在当前VC内修改这个属性就可以解决这个问题了. 当前以TableView为主View的ViewCon ...
- solr 查询 实例分析
solr索引查询接口:http://localhost:8080/solr/query 首先了解一下查询参数的含义. q Solr 中用来搜索的查询.可以通过追加一个分号和已索引且未进行断词的字段(下 ...
- 【第三课】WEBIX 入门自学-Hello World
在看官网教程时,入门的例子就是dataTable这个空间.So,遵循官网,一起来看一下入门的DataTable组件: WEB使用时固然是先引入相应的库文件: 代码如下 <html> < ...
- weex逻辑控制
在WEEX中,有if 和 repeat 两种逻辑运算,需要注意的是,逻辑控制不能够作用于<template>这样的根节点. if 控制判断条件true/false直接对节点进行操作,if= ...
- 踏上Salesforce的学习之路(三)
一.创建Invoice对象 为了使我们的这个Warehouse app更加接近现实,我们现在为他创建一个Invoice对象. 先点击右上角的Setup,然后在左侧的Quick Find查找框中输入Ob ...