一、题目一:二叉树的深度

1.1 题目说明

题目一:输入一棵二叉树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。例如下图中的二叉树的深度为4,因为它从根结点到叶结点最长的路径包含4个结点(从根结点1开始,经过结点2和结点5,最终到达叶结点7)。

  二叉树的结点定义如下,这里使用C#语言描述:

  1. public class BinaryTreeNode
  2. {
  3. public int Data { get; set; }
  4. public BinaryTreeNode LeftChild { get; set; }
  5. public BinaryTreeNode RightChild { get; set; }
  6.  
  7. public BinaryTreeNode(int data)
  8. {
  9. this.Data = data;
  10. }
  11.  
  12. public BinaryTreeNode(int data, BinaryTreeNode left, BinaryTreeNode right)
  13. {
  14. this.Data = data;
  15. this.LeftChild = left;
  16. this.RightChild = right;
  17. }
  18. }

1.2 解题思路

  ①如果一棵树只有一个结点,它的深度为1。

  ②如果根结点只有左子树而没有右子树,那么树的深度应该是其左子树的深度加1;同样如果根结点只有右子树而没有左子树,那么树的深度应该是其右子树的深度加1。

  ③如果既有右子树又有左子树,那该树的深度就是其左、右子树深度的较大值再加1。

  比如在上图的二叉树中,根结点为1的树有左右两个子树,其左右子树的根结点分别为结点2和3。根结点为2的左子树的深度为3,而根结点为3的右子树的深度为2,因此根结点为1的树的深度就是4。

  1. public static int GetTreeDepth(BinaryTreeNode root)
  2. {
  3. if (root == null)
  4. {
  5. return ;
  6. }
  7.  
  8. int left = GetTreeDepth(root.LeftChild);
  9. int right = GetTreeDepth(root.RightChild);
  10.  
  11. return left >= right ? left + : right + ;
  12. }

1.3 单元测试

  (1)测试用例

  1. [TestClass]
  2. public class TreeDepthTest
  3. {
  4. private void SetSubTreeNode(BinaryTreeNode root, BinaryTreeNode lChild, BinaryTreeNode rChild)
  5. {
  6. if (root == null)
  7. {
  8. return;
  9. }
  10.  
  11. root.LeftChild = lChild;
  12. root.RightChild = rChild;
  13. }
  14.  
  15. private void ClearUpTreeNode(BinaryTreeNode root)
  16. {
  17. if (root != null)
  18. {
  19. BinaryTreeNode left = root.LeftChild;
  20. BinaryTreeNode right = root.RightChild;
  21.  
  22. root = null;
  23.  
  24. ClearUpTreeNode(left);
  25. ClearUpTreeNode(right);
  26. }
  27. }
  28.  
  29. // 1
  30. // / \
  31. // 2 3
  32. // /\ \
  33. // 4 5 6
  34. // /
  35. //
  36. [TestMethod]
  37. public void GetDepthTest1()
  38. {
  39. BinaryTreeNode node1 = new BinaryTreeNode();
  40. BinaryTreeNode node2 = new BinaryTreeNode();
  41. BinaryTreeNode node3 = new BinaryTreeNode();
  42. BinaryTreeNode node4 = new BinaryTreeNode();
  43. BinaryTreeNode node5 = new BinaryTreeNode();
  44. BinaryTreeNode node6 = new BinaryTreeNode();
  45. BinaryTreeNode node7 = new BinaryTreeNode();
  46.  
  47. SetSubTreeNode(node1, node2, node3);
  48. SetSubTreeNode(node2, node4, node5);
  49. SetSubTreeNode(node3, null, node6);
  50. SetSubTreeNode(node5, node7, null);
  51.  
  52. int actual = TreeDepthHelper.GetTreeDepth(node1);
  53. Assert.AreEqual(actual, );
  54.  
  55. ClearUpTreeNode(node1);
  56. }
  57.  
  58. // 1
  59. // /
  60. // 2
  61. // /
  62. // 3
  63. // /
  64. // 4
  65. // /
  66. //
  67. [TestMethod]
  68. public void GetDepthTest2()
  69. {
  70. BinaryTreeNode node1 = new BinaryTreeNode();
  71. BinaryTreeNode node2 = new BinaryTreeNode();
  72. BinaryTreeNode node3 = new BinaryTreeNode();
  73. BinaryTreeNode node4 = new BinaryTreeNode();
  74. BinaryTreeNode node5 = new BinaryTreeNode();
  75.  
  76. SetSubTreeNode(node1, node2, null);
  77. SetSubTreeNode(node2, node3, null);
  78. SetSubTreeNode(node3, node4, null);
  79. SetSubTreeNode(node4, node5, null);
  80.  
  81. int actual = TreeDepthHelper.GetTreeDepth(node1);
  82. Assert.AreEqual(actual, );
  83.  
  84. ClearUpTreeNode(node1);
  85. }
  86.  
  87. // 1
  88. // \
  89. // 2
  90. // \
  91. // 3
  92. // \
  93. // 4
  94. // \
  95. //
  96. [TestMethod]
  97. public void GetDepthTest3()
  98. {
  99. BinaryTreeNode node1 = new BinaryTreeNode();
  100. BinaryTreeNode node2 = new BinaryTreeNode();
  101. BinaryTreeNode node3 = new BinaryTreeNode();
  102. BinaryTreeNode node4 = new BinaryTreeNode();
  103. BinaryTreeNode node5 = new BinaryTreeNode();
  104.  
  105. SetSubTreeNode(node1, null, node2);
  106. SetSubTreeNode(node2, null, node3);
  107. SetSubTreeNode(node3, null, node4);
  108. SetSubTreeNode(node4, null, node5);
  109.  
  110. int actual = TreeDepthHelper.GetTreeDepth(node1);
  111. Assert.AreEqual(actual, );
  112.  
  113. ClearUpTreeNode(node1);
  114. }
  115.  
  116. // 树中只有1个结点
  117. [TestMethod]
  118. public void GetDepthTest4()
  119. {
  120. BinaryTreeNode node1 = new BinaryTreeNode();
  121.  
  122. int actual = TreeDepthHelper.GetTreeDepth(node1);
  123. Assert.AreEqual(actual, );
  124.  
  125. ClearUpTreeNode(node1);
  126. }
  127.  
  128. // 树中没有结点
  129. [TestMethod]
  130. public void GetDepthTest5()
  131. {
  132. int actual = TreeDepthHelper.GetTreeDepth(null);
  133. Assert.AreEqual(actual, );
  134. }
  135. }

  (2)测试结果

  ①测试通过情况

  ②代码覆盖率

二、题目二:判断二叉树是否是平衡二叉树

2.1 题目说明

题目二:输入一棵二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。例如,下图中的二叉树就是一棵平衡二叉树。

2.2 解题思路

  (1)需要重复遍历节点多次的解法

  有了求二叉树的深度的经验之后再解决这个问题,我们很容易就能想到一个思路:在遍历树的每个结点的时候,调用函数TreeDepth得到它的左右子树的深度。如果每个结点的左右子树的深度相差都不超过1,按照定义它就是一棵平衡的二叉树。

  1. public static bool IsBalancedBinaryTree(BinaryTreeNode root)
  2. {
  3. if (root == null)
  4. {
  5. return true;
  6. }
  7.  
  8. int left = GetTreeDepth(root.LeftChild);
  9. int right = GetTreeDepth(root.RightChild);
  10. int diff = left - right;
  11.  
  12. if (diff > || diff < -)
  13. {
  14. return false;
  15. }
  16.  
  17. return IsBalancedBinaryTree(root.LeftChild) && IsBalancedBinaryTree(root.RightChild);
  18. }

  上面的代码固然简洁,但我们也要注意到由于一个结点会被重复遍历多次,这种思路的时间效率不高。例如在IsBalancedBinaryTree方法中输入上图中的二叉树,我们将首先判断根结点(结点1)是不是平衡的。此时我们往函数TreeDepth输入左子树的根结点(结点2)时,需要遍历结点4、5、7。接下来判断以结点2为根结点的子树是不是平衡树的时候,仍然会遍历结点4、5、7。毫无疑问,重复遍历同一个结点会影响性能

  (2)每个节点只需遍历一次的解法

  换个角度来思考,如果我们用后序遍历的方式遍历二叉树的每一个结点,在遍历到一个结点之前我们就已经遍历了它的左右子树。只要在遍历每个结点的时候记录它的深度(某一结点的深度等于它到叶节点的路径的长度),我们就可以一边遍历一边判断每个结点是不是平衡的。

  1. public static bool IsBalancedBinaryTree(BinaryTreeNode root)
  2. {
  3. int depth = ;
  4. return IsBalancedBinaryTreeCore(root, ref depth);
  5. }
  6.  
  7. private static bool IsBalancedBinaryTreeCore(BinaryTreeNode root, ref int depth)
  8. {
  9. if (root == null)
  10. {
  11. depth = ;
  12. return true;
  13. }
  14.  
  15. int left = ;
  16. int right = ;
  17. if (IsBalancedBinaryTreeCore(root.LeftChild, ref left) && IsBalancedBinaryTreeCore(root.RightChild, ref right))
  18. {
  19. int diff = left - right;
  20. if (diff >= - && diff <= )
  21. {
  22. depth = left >= right ? left + : right + ;
  23. return true;
  24. }
  25. }
  26.  
  27. return false;
  28. }

  在上面的代码中,我们用后序遍历的方式遍历整棵二叉树。在遍历某结点的左右子结点之后,我们可以根据它的左右子结点的深度判断它是不是平衡的,并得到当前结点的深度。当最后遍历到树的根结点的时候,也就判断了整棵二叉树是不是平衡二叉树。

2.3 单元测试

  此方法的单元测试和第一种方法的一致,这里就不再贴出。需要注意的就是在针对二叉树的测试用例中,需要考虑两种:功能测试(平衡的二叉树,不是平衡的二叉树,二叉树中所有结点都没有左/右子树)。特殊输入测试(二叉树中只有一个结点,二叉树的头结点为NULL指针)。

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

剑指Offer面试题:33.二叉树的深度的更多相关文章

  1. 剑指Offer - 九度1350 - 二叉树的深度

    剑指Offer - 九度1350 - 二叉树的深度2013-11-23 00:54 题目描述: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的 ...

  2. 剑指offer【08】- 二叉树的深度(java)

    题目:二叉树的深度 考点:知识迁移能力 题目描述:输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 牛客网上的剑指offer题, ...

  3. 【剑指offer】55 - I. 二叉树的深度

    剑指 Offer 55 - I. 二叉树的深度 知识点:二叉树,递归 题目描述 输入一棵二叉树的根节点,求该树的深度.从根节点到叶节点依次经过的节点(含根.叶节点)形成树的一条路径,最长路径的长度为树 ...

  4. 剑指Offer:面试题25——二叉树中和为某一值的路径(java实现)

    问题描述: 输入一棵二叉树和一个整数,打印出二叉树中结点指的和为输入整数的所有路径.从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.二叉树结点的定义如下: public class Tree ...

  5. 剑指Offer:面试题19——二叉树的镜像(java实现)

    问题描述: 操作给定的二叉树,将其变换为源二叉树的镜像. 二叉树结点定义为: public class TreeNode { int val = 0; TreeNode left = null; Tr ...

  6. 剑指offer面试题19 二叉树的镜像

    题目描述 操作给定的二叉树,将其变换为源二叉树的镜像.  输入描述 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ ...

  7. 剑指Offer面试题33(java版):把数组排成最小的数

    题目:输入一个正整数数组.把数组里面全部的数字拼接排成一个数,打印能拼接出的全部数字中的一个.比如输入数组{3,32.321}.则打印出这3个数字能排成的最小数字321323. 这个题目最直接的做法应 ...

  8. 剑指Offer:面试题33——把数组排成最小的数(java实现)(未完待续)

    问题描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 思路1: ...

  9. 剑指offer(38)二叉树的深度

    题目描述 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 题目分析 树的深度=左子树的深度和右子树深度中最大者+1 代码 fu ...

  10. 【剑指Offer】38、二叉树的深度

      题目描述:   输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度.   解题思路:   本题相对比较简单.根据二叉树深度的定义 ...

随机推荐

  1. GruntJS学习(转)

    GruntJS 是基于JavaScript的命令行构建工具,它可以帮助开发者们自动化重复性的工作.你可以把它看成是JavaScript下的Make或者Ant.它可以完成诸如精简.编译.单元测试.lin ...

  2. git使用

    1.权限校验 首先,您的数据保存在远端服务器一份,服务器需要对您的身份进行识别,一段RAS加密字串, 启动GUI,step1:创建秘钥,generate SSHkey. step2:添加密钥:去你的代 ...

  3. [spring源码学习]四、IOC源码——普通bean初始化

    一.代码例子 此节开始涉及到一个bean具体生成和保存的过程,仅仅涉及到最简单的bean,代码依旧是最简单的 public static void main(String[] args) { Defa ...

  4. openfl使用64位的ndk时,编译报错的问题!

    当使用64位的ndk时,如果使用openfl test android运行android测试,应该会出现 arm-linux-androideabi-g++:找不到这个命令的错误. 原因是,haxel ...

  5. Sprint2团队贡献分

    团队贡献分: 郭志豪:31%  http://www.cnblogs.com/gzh13692021053/ 杨子健:22%http://www.cnblogs.com/yzj666/ 谭宇森:23% ...

  6. iOS automaticallyAdjustsScrollViewInsets

    self.automaticallyAdjustsScrollViewInsets = NO; //在当前VC内修改这个属性就可以解决这个问题了. 当前以TableView为主View的ViewCon ...

  7. solr 查询 实例分析

    solr索引查询接口:http://localhost:8080/solr/query 首先了解一下查询参数的含义. q Solr 中用来搜索的查询.可以通过追加一个分号和已索引且未进行断词的字段(下 ...

  8. 【第三课】WEBIX 入门自学-Hello World

    在看官网教程时,入门的例子就是dataTable这个空间.So,遵循官网,一起来看一下入门的DataTable组件: WEB使用时固然是先引入相应的库文件: 代码如下 <html> < ...

  9. weex逻辑控制

    在WEEX中,有if 和 repeat 两种逻辑运算,需要注意的是,逻辑控制不能够作用于<template>这样的根节点. if 控制判断条件true/false直接对节点进行操作,if= ...

  10. 踏上Salesforce的学习之路(三)

    一.创建Invoice对象 为了使我们的这个Warehouse app更加接近现实,我们现在为他创建一个Invoice对象. 先点击右上角的Setup,然后在左侧的Quick Find查找框中输入Ob ...