题目:输入一棵二叉树的根节点,求该数的深度。

从根节点到叶结点依次进过的结点(含根,叶结点)形成树的一条路径,最长路径的长度为树的深度。

比如。例如以下图的二叉树的深度为4。由于它从根节点到叶结点的最长的路径包括4个结点(从根结点1開始,经过2和结点5,终于到达叶结点7)

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

我们能够从还有一种角度来理解树的深度。

假设一棵树仅仅有一个结点,它的深度为1,假设根节点仅仅有左子树而没有右子树,那么树的深度应该是其左子树的深度+1.相同假设根节点仅仅有右子树而没有左子树,那么树的深度应该是其右子树+1.假设既有左子树又有右子树。那概述的深度就是左、右子树的深度的较大值加1.。

利用这个思路,我们能够用递归来实现代码:

//普通二叉树求深度
public int treeDepth(BinaryTreeNode root){
if(root == null)
return 0;
int nLeft = treeDepth(root.leftNode);
int nRight = treeDepth(root.rightNode);
return (nLeft > nRight)? (nLeft+1):(nRight+1);
}

假设公司对编程能力有较高的要求。面试官可能会追加一个与前面的问题相关但难度较大的问题,比方,应聘者做完上面的问题后,面试官追问:

题目二:输入一棵二叉树的根节点。推断该树是不是平衡的二叉树。假设某二叉树中随意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

须要反复遍历结点多次的解法,简单但不足以打动面试官

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

这样的思路实现的代码例如以下:

//推断是否是一颗平衡二叉树
public boolean isBalanced(BinaryTreeNode root){
if(root ==null)
return true;
int left = treeDepth(root.leftNode);
int right = treeDepth(root.rightNode);
int diff = left - right;
if(diff > 1 || diff <-1)
return false;
return isBalanced(root.leftNode) && isBalanced(root.rightNode);
}

上面的代码固然简洁,但我们也注意到因为一个结点会被反复遍历多次,这样的思路的时间效率不高。

比如在函数isBalanced中输入上图中的二叉树,我们将首先推断根节点是不是平衡的。

此时我们网函数TreeDepth输入左子树的根节点时须要遍历结点4,5。7.接下来推断以结点2为根节点的子树是不是平衡树的时候。仍然会遍历结点4,5,7.毫无疑问,反复遍历同一个结点会影响性能。接下来我们寻找不须要反复遍历的算法。

每一个结点仅仅遍历一次的解法,正是面试官喜欢的算法

假设我们用后序遍历的方式遍历二叉树的每一个结点。在遍历一个结点之前我们就已经遍历了它的左右子树。仅仅要在遍历每一个结点的时候我们记录它的深度(某一节点的深度等于它到叶结点的路径的长度),我们就能够一边遍历一边推断每一个结点是不是平衡二叉树。

以下是这样的思路的实现代码:

//高效率的推断是否是一棵平衡二叉树
public boolean isBalanced2(BinaryTreeNode root){
int depth = 0;
return isBalanced2(root,depth);
}
public boolean isBalanced2(BinaryTreeNode root,int depth){
if(root == null){
depth = 0;
return true;
}
int left = 0,right = 0;
if(isBalanced2(root.leftNode,left) && isBalanced2(root.rightNode,right)){
int diff = left-right;
if(diff <= 1 && diff >= -1){
depth = 1+(left > right?left : right);
return true;
}
}
return false;
}

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

剑指Offer面试题39(Java版):二叉树的深度的更多相关文章

  1. 剑指offer面试题14(Java版):调整数组顺序使奇数位于偶数的前面

    题目:输入一个整数数组.实现一个函数来调整该数组中数字的顺序.使得全部奇数位于数组的前半部分.全部偶数位于数组的后半部分. 1.基本实现: 假设不考虑时间复杂度,最简单的思路应该是从头扫描这个数组,每 ...

  2. C++版 - 剑指offer 面试题39:判断平衡二叉树(LeetCode 110. Balanced Binary Tree) 题解

    剑指offer 面试题39:判断平衡二叉树 提交网址:  http://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId= ...

  3. C++版 - 剑指Offer 面试题39:二叉树的深度(高度)(二叉树深度优先遍历dfs的应用) 题解

    剑指Offer 面试题39:二叉树的深度(高度) 题目:输入一棵二叉树的根结点,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度.例如:输入二叉树 ...

  4. 剑指offer面试题:输入某二叉树的前序遍历和中序遍历,输出后序遍历

    二叉树的先序,中序,后序如何遍历,不在此多说了.直接看题目描述吧(题目摘自九度oj剑指offer面试题6): 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结 ...

  5. C++版-剑指offer 面试题6:重建二叉树(Leetcode105. Construct Binary Tree from Preorder and Inorder Traversal) 解题报告

    剑指offer 重建二叉树 提交网址: http://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tq ...

  6. 剑指offer面试题6:重建二叉树

    1.题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树. public class Solution { public TreeNode reConstructBinaryTree(int ...

  7. 剑指offer——面试题7:重建二叉树

    // 面试题7:重建二叉树 // 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输 // 入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1, // 2, ...

  8. 剑指Offer第36题—Java版

    本题使用归并排序的思想,结合归并排序,写出的算法解. //数组中的逆序对 public static int InversePairs(int[] array){ if(array==null||ar ...

  9. [刷题] 剑指Offer 面试题7:重建二叉树

    题目:输入某二叉树的前序遍历和中序遍历结果,重建该二叉树.(假设输入的前序和中序遍历结果中都不含重复数字) 思路 构建二叉树的两个函数:Construct().ConstructCore() Cons ...

随机推荐

  1. windows服务器下iis的性能优化 服务器

    IIS性能优化 1.调整IIS高速缓存 HKEY_LOCAL_MACHINE SystemCurrentControlSetServicesInetInfoParametersMemoryCacheS ...

  2. C#中获取当前系统中安装的所有字体及预定义颜色

    需要引用命名空间using System.Drawing.Text;.... //获取系统字体:InstalledFontCollection fc = new InstalledFontCollec ...

  3. vim如何显示行号

    在 vim 里执行(在普通模式下直接按冒号,并输入下面的命令 :set number 回车后就可以显示行号了,但重启 vim 后又会恢复默认的设置. 要想每次进入 vim 都显示行号就需要配置 vim ...

  4. 前端框架:react还是vue?

    之前写了一篇前端框架的大汇总,主要介绍了当下主流的框架和其特性.最近除了bootstrap,就属react和vue最为热门,这篇就主要拿这两个框架来做一下详细对比. 究竟如何正确使用?作为小白的我们从 ...

  5. C#版本websocket及时通信协议实现

    1:Websocket有java.nodejs.python.PHP.等版本 ,我现在使用的是C3版本,服务器端是Fleck.客户端和服务器端来使用websocket的,下面开始讲解如何使用: 2:在 ...

  6. 微信JS-SDK 选取手机照片并进行上传

    项目中遇到需要选取照片上传的需求,因为网页运行在微信的浏览器里面,所以用微信的 js-sdk 提供的选取照片功能,来进行项目开发.实际开发中需要用到微信web开发者工具,详细参考链接:https:// ...

  7. 非关系型数据库redis-java基本操作

    概述 redis是一个key-value的nosql数据库(非关系型数据库).支持存储的value类型包括string(字符串).list(链表).set(集合).zset(sorted set -- ...

  8. prometheus client_golang使用

    序言 Prometheus是一个开源的监控系统,拥有许多Advanced Feature,他会定期用HTTP协议来pull所监控系统状态进行数据收集,在加上timestamp等数据组织成time se ...

  9. Iterator & Iterable 和 Comparable&Comparator

    java.lang.Iterator & java.lang.Iterable Iterator和Iterable的区别和联系 iterator是具有迭代状态的对象.它允许你检查它是否有更多的 ...

  10. Python 日志处理(二) 使用正则表达式处理Nginx 日志

    使用正则表达式来处理Nginx 日志 一. 先对单行的日志进行分组正则匹配,返回匹配后的结果(字典格式): from datetime import datetime import re #单行日志 ...