算法之乐:一个算法解决3道经典二叉树面试题(深度、长度、直径)
来源:互联网 发布:淘宝商城客服 编辑:程序博客网 时间:2024/05/22 06:48
有了昨天《Java实现二叉树的构建以及3种遍历方法》的二叉树数据结构基础,今天我们通过一个算法解决3道关于二叉树的经典面试题(深度、长度、直径),触类旁通,举一反三,尽享算法之乐。
测试二叉树:
例题:给定一个二叉树,计算它的最大深度。深度是指根节点到子节点路径中的节点个数。
如图,1->8/9的深度为4(1-2-4-8/9),这也是这棵二叉树的最大深度。
我们定义一个Result类,里面包含一个整型变量nMaxDepth,并重写它的toString方法。
private static class Result { int nMaxDepth;//深度,根节点到子节点路径中的节点个数。 @Override public String toString() { return "nMaxDepth:" + nMaxDepth; }};
result.nMaxDepth = 1+ Math.max(leftResult.nMaxDepth, rightResult.nMaxDepth);
结合实例:从根节点1开始,先求他左子树的最大深度,来到2,继续求它左子树的最大深度,···,1-2-4-8,
此时对于8,1+ Max(左子树的最大深度, 右子树的最大深度)=1+(0,0)=1:
root.leftChild:null
leftResult:nMaxDepth:0
root.rightChild:null
rightResult:nMaxDepth:0
root.leftChild:data:8,leftChild:null,rightChild:null
leftResult:nMaxDepth:1
然后退到4,求它右子树的最大深度,进到9,1+ Max(左子树的最大深度, 右子树的最大深度)=1+(0,0)=1:
root.leftChild:null
leftResult:nMaxDepth:0
root.rightChild:null
rightResult:nMaxDepth:0
root.rightChild:data:9,leftChild:null,rightChild:null
rightResult:nMaxDepth:1
回到4=1+ Max(左子树的最大深度, 右子树的最大深度)=1+(1,1)=2:
root.leftChild:data:4,leftChild:data:8,leftChild:null,rightChild:null,rightChild:data:9,leftChild:null,rightChild:null
leftResult:nMaxDepth:2
回到2,进到5=1+ Max(左子树的最大深度, 右子树的最大深度)=1+(0,0)=1:
root.leftChild:null
leftResult:nMaxDepth:0
root.rightChild:null
rightResult:nMaxDepth:0
root.rightChild:data:5,leftChild:null,rightChild:null
rightResult:nMaxDepth:1
退回到2=1+ Max(左子树的最大深度, 右子树的最大深度)=1+(2,1)=3:
root.leftChild:data:2,leftChild:data:4,leftChild:data:8,leftChild:null,rightChild:null,rightChild:data:9,leftChild:null,rightChild:null,rightChild:data:5,leftChild:null,rightChild:null
leftResult:nMaxDepth:3
同理求1的右子树,1-3-6(1)-7(1)-3(2)-1(4)。
我们看一下算法的Java实现:
public static Result compDiameter(Node root) {if (root == null) {Result empty = new Result();empty.nMaxDepth = 0;return empty;}Result leftResult = compDiameter(root.leftChild);System.out.println("root.leftChild:" + root.leftChild);System.out.println("leftResult:" + leftResult);Result rightResult = compDiameter(root.rightChild);System.out.println("root.rightChild:" + root.rightChild);System.out.println("rightResult:" + rightResult);Result result = new Result();result.nMaxDepth = 1+ Math.max(leftResult.nMaxDepth, rightResult.nMaxDepth); return result;}
root.leftChild:null
leftResult:nMaxDepth:0
root.rightChild:null
rightResult:nMaxDepth:0
root.leftChild:data:8,leftChild:null,rightChild:null
leftResult:nMaxDepth:1
root.leftChild:null
leftResult:nMaxDepth:0
root.rightChild:null
rightResult:nMaxDepth:0
root.rightChild:data:9,leftChild:null,rightChild:null
rightResult:nMaxDepth:1
root.leftChild:data:4,leftChild:data:8,leftChild:null,rightChild:null,rightChild:data:9,leftChild:null,rightChild:null
leftResult:nMaxDepth:2
root.leftChild:null
leftResult:nMaxDepth:0
root.rightChild:null
rightResult:nMaxDepth:0
root.rightChild:data:5,leftChild:null,rightChild:null
rightResult:nMaxDepth:1
root.leftChild:data:2,leftChild:data:4,leftChild:data:8,leftChild:null,rightChild:null,rightChild:data:9,leftChild:null,rightChild:null,rightChild:data:5,leftChild:null,rightChild:null
leftResult:nMaxDepth:3
root.leftChild:null
leftResult:nMaxDepth:0
root.rightChild:null
rightResult:nMaxDepth:0
root.leftChild:data:6,leftChild:null,rightChild:null
leftResult:nMaxDepth:1
root.leftChild:null
leftResult:nMaxDepth:0
root.rightChild:null
rightResult:nMaxDepth:0
root.rightChild:data:7,leftChild:null,rightChild:null
rightResult:nMaxDepth:1
root.rightChild:data:3,leftChild:data:6,leftChild:null,rightChild:null,rightChild:data:7,leftChild:null,rightChild:null
rightResult:nMaxDepth:2
计算结果:nMaxDepth:4
稍微回味一下,我们举一反二:
变体:给定一个二叉树,计算它的最大长度。长度是指二叉树两个节点之间的路径中边的个数。
如图,最大长度为8/9-6/7=5,
结合例题的基础分析,最大长度=左子树最大深度+右子树最大深度,5=3+2。
result.nMaxDistance = leftResult.nMaxDepth + rightResult.nMaxDepth
我们在Result类中追加长度变量nMaxDistance,并重写toString方法。
private static class Result { int nMaxDepth;//深度,根节点到子节点路径中的节点个数。 int nMaxDistance;//长度,二叉树两个节点之间的路径中边的个数。 @Override public String toString() { return "nMaxDepth:" + nMaxDepth + ",nMaxDistance:" + nMaxDistance; }};
在核心算法中添加2行代码:
1.当根节点为空时,empty.nMaxDistance = 0;
2.长度计算:result.nMaxDistance = leftResult.nMaxDepth + rightResult.nMaxDepth;
public static Result compDiameter(Node root) {if (root == null) {Result empty = new Result();empty.nMaxDepth = 0;empty.nMaxDistance = 0;return empty;}Result leftResult = compDiameter(root.leftChild);System.out.println("root.leftChild:" + root.leftChild);System.out.println("leftResult:" + leftResult);Result rightResult = compDiameter(root.rightChild);System.out.println("root.rightChild:" + root.rightChild);System.out.println("rightResult:" + rightResult);Result result = new Result();result.nMaxDepth = 1+ Math.max(leftResult.nMaxDepth, rightResult.nMaxDepth); result.nMaxDistance = leftResult.nMaxDepth + rightResult.nMaxDepth;return result;}
过程类似,输出结果:
root.leftChild:null
leftResult:nMaxDepth:0,nMaxDistance:0
root.rightChild:null
rightResult:nMaxDepth:0,nMaxDistance:0
root.leftChild:data:8,leftChild:null,rightChild:null
leftResult:nMaxDepth:1,nMaxDistance:0
root.leftChild:null
leftResult:nMaxDepth:0,nMaxDistance:0
root.rightChild:null
rightResult:nMaxDepth:0,nMaxDistance:0
root.rightChild:data:9,leftChild:null,rightChild:null
rightResult:nMaxDepth:1,nMaxDistance:0
root.leftChild:data:4,leftChild:data:8,leftChild:null,rightChild:null,rightChild:data:9,leftChild:null,rightChild:null
leftResult:nMaxDepth:2,nMaxDistance:2
root.leftChild:null
leftResult:nMaxDepth:0,nMaxDistance:0
root.rightChild:null
rightResult:nMaxDepth:0,nMaxDistance:0
root.rightChild:data:5,leftChild:null,rightChild:null
rightResult:nMaxDepth:1,nMaxDistance:0
root.leftChild:data:2,leftChild:data:4,leftChild:data:8,leftChild:null,rightChild:null,rightChild:data:9,leftChild:null,rightChild:null,rightChild:data:5,leftChild:null,rightChild:null
leftResult:nMaxDepth:3,nMaxDistance:3
root.leftChild:null
leftResult:nMaxDepth:0,nMaxDistance:0
root.rightChild:null
rightResult:nMaxDepth:0,nMaxDistance:0
root.leftChild:data:6,leftChild:null,rightChild:null
leftResult:nMaxDepth:1,nMaxDistance:0
root.leftChild:null
leftResult:nMaxDepth:0,nMaxDistance:0
root.rightChild:null
rightResult:nMaxDepth:0,nMaxDistance:0
root.rightChild:data:7,leftChild:null,rightChild:null
rightResult:nMaxDepth:1,nMaxDistance:0
root.rightChild:data:3,leftChild:data:6,leftChild:null,rightChild:null,rightChild:data:7,leftChild:null,rightChild:null
rightResult:nMaxDepth:2,nMaxDistance:2
计算结果:nMaxDepth:4,nMaxDistance:5
稍加回味一下,我们举一反三:
变体:给定一个二叉树,计算它的直径。直径是指节点之间最长路径中节点个数。
如图,直径为8/9-6/7=6,
有了之前2道题的基础,直径=根节点(1)+左子树最大深度+右子树最大深度=1+最大长度。
result.nodeNum = 1 + leftResult.nMaxDepth + rightResult.nMaxDepth = 1 + nMaxDistance;我们追加直径变量nodeNum并重写toString方法:
private static class Result { int nMaxDepth;//深度,根节点到子节点路径中的节点个数。 int nMaxDistance;//长度,二叉树两个节点之间的路径中边的个数。 int nodeNum;//直径,节点之间最长路径中节点个数。 @Override public String toString() { return "nodeNum:" + nodeNum + ",nMaxDistance:" + nMaxDistance + ",nMaxDepth:" + nMaxDepth; }};
在核心算法中添加2行代码:
1.当根节点为空时,empty.nodeNum = 0;;
2.直径计算:result.nodeNum = 1 + leftResult.nMaxDepth + rightResult.nMaxDepth;
过程类似,输出结果:root.leftChild:null
leftResult:nodeNum:0,nMaxDistance:0,nMaxDepth:0
root.rightChild:null
rightResult:nodeNum:0,nMaxDistance:0,nMaxDepth:0
root.leftChild:data:8,leftChild:null,rightChild:null
leftResult:nodeNum:1,nMaxDistance:0,nMaxDepth:1
root.leftChild:null
leftResult:nodeNum:0,nMaxDistance:0,nMaxDepth:0
root.rightChild:null
rightResult:nodeNum:0,nMaxDistance:0,nMaxDepth:0
root.rightChild:data:9,leftChild:null,rightChild:null
rightResult:nodeNum:1,nMaxDistance:0,nMaxDepth:1
root.leftChild:data:4,leftChild:data:8,leftChild:null,rightChild:null,rightChild:data:9,leftChild:null,rightChild:null
leftResult:nodeNum:3,nMaxDistance:2,nMaxDepth:2
root.leftChild:null
leftResult:nodeNum:0,nMaxDistance:0,nMaxDepth:0
root.rightChild:null
rightResult:nodeNum:0,nMaxDistance:0,nMaxDepth:0
root.rightChild:data:5,leftChild:null,rightChild:null
rightResult:nodeNum:1,nMaxDistance:0,nMaxDepth:1
root.leftChild:data:2,leftChild:data:4,leftChild:data:8,leftChild:null,rightChild:null,rightChild:data:9,leftChild:null,rightChild:null,rightChild:data:5,leftChild:null,rightChild:null
leftResult:nodeNum:4,nMaxDistance:3,nMaxDepth:3
root.leftChild:null
leftResult:nodeNum:0,nMaxDistance:0,nMaxDepth:0
root.rightChild:null
rightResult:nodeNum:0,nMaxDistance:0,nMaxDepth:0
root.leftChild:data:6,leftChild:null,rightChild:null
leftResult:nodeNum:1,nMaxDistance:0,nMaxDepth:1
root.leftChild:null
leftResult:nodeNum:0,nMaxDistance:0,nMaxDepth:0
root.rightChild:null
rightResult:nodeNum:0,nMaxDistance:0,nMaxDepth:0
root.rightChild:data:7,leftChild:null,rightChild:null
rightResult:nodeNum:1,nMaxDistance:0,nMaxDepth:1
root.rightChild:data:3,leftChild:data:6,leftChild:null,rightChild:null,rightChild:data:7,leftChild:null,rightChild:null
rightResult:nodeNum:3,nMaxDistance:2,nMaxDepth:2
计算结果:nodeNum:6,nMaxDistance:5,nMaxDepth:4
多思考,举一反三,在算法的海洋里遨游。
最后附上包括建树、遍历等操作的完整源代码,原创不易,转载请注明出处哈。
权兴权意-算法之乐:一个算法解决3道经典二叉树面试题(深度、长度、直径)
http://blog.csdn.net/hxqneuq2012/article/details/52766162
import java.util.LinkedList;import java.util.List;public class BinaryTree {private int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };private static List<Node> nodeList = new LinkedList<Node>();;private static class Node {Node leftChild;Node rightChild;int data;Node(int newData) {leftChild = null;rightChild = null;data = newData;}@Overridepublic String toString() {return "data:" + data + ",leftChild:" + leftChild + ",rightChild:"+ rightChild;}}private static class Result { int nMaxDepth;//深度,根节点到子节点路径中的节点个数。 int nMaxDistance;//长度,二叉树两个节点之间的路径中边的个数。 int nodeNum;//直径,节点之间最长路径中节点个数。 @Override public String toString() { return "nodeNum:" + nodeNum + ",nMaxDistance:" + nMaxDistance + ",nMaxDepth:" + nMaxDepth; }// @Override// public String toString() {// return "nMaxDepth:" + nMaxDepth + ",nMaxDistance:" + nMaxDistance;// }}; /* * 给定一个二叉树,计算它的深度、长度、直径。 * 深度,根节点到子节点路径中的节点个数。 * 长度,二叉树两个节点之间的路径中边的个数。 * 直径,节点之间最长路径中节点个数。 */public static Result compDiameter(Node root) {if (root == null) {Result empty = new Result();empty.nMaxDepth = 0;empty.nMaxDistance = 0;empty.nodeNum = 0;return empty;}Result leftResult = compDiameter(root.leftChild);System.out.println("root.leftChild:" + root.leftChild);System.out.println("leftResult:" + leftResult);Result rightResult = compDiameter(root.rightChild);System.out.println("root.rightChild:" + root.rightChild);System.out.println("rightResult:" + rightResult);Result result = new Result();result.nMaxDepth = 1+ Math.max(leftResult.nMaxDepth, rightResult.nMaxDepth); result.nMaxDistance = leftResult.nMaxDepth + rightResult.nMaxDepth; result.nodeNum = 1 + leftResult.nMaxDepth + rightResult.nMaxDepth;return result;}public void createBinTree() {// 将一个数组的值依次转换为Node节点for (int nodeIndex = 0; nodeIndex < array.length; nodeIndex++) {nodeList.add(new Node(array[nodeIndex]));}// 对前lastParentIndex-1个父节点按照父节点与孩子节点的数字关系建立二叉树for (int parentIndex = 0; parentIndex < array.length / 2 - 1; parentIndex++) {// 左孩子nodeList.get(parentIndex).leftChild = nodeList.get(parentIndex * 2 + 1);// 右孩子nodeList.get(parentIndex).rightChild = nodeList.get(parentIndex * 2 + 2);}// 最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独拿出来处理int lastParentIndex = array.length / 2 - 1;// 左孩子nodeList.get(lastParentIndex).leftChild = nodeList.get(lastParentIndex * 2 + 1);// 右孩子,如果数组的长度为奇数才建立右孩子if (array.length % 2 == 1) {nodeList.get(lastParentIndex).rightChild = nodeList.get(lastParentIndex * 2 + 2);}}/** * 先序遍历 */public static void preOrderTraverse(Node node) {if (node == null)return;System.out.print(node.data + " ");preOrderTraverse(node.leftChild);preOrderTraverse(node.rightChild);}/** * 中序遍历 */public static void inOrderTraverse(Node node) {if (node == null)return;inOrderTraverse(node.leftChild);System.out.print(node.data + " ");inOrderTraverse(node.rightChild);}/** * 后序遍历 */public static void postOrderTraverse(Node node) {if (node == null)return;postOrderTraverse(node.leftChild);postOrderTraverse(node.rightChild);System.out.print(node.data + " ");}/** * 权兴权意-2016.10.8 */public static void main(String[] args) {BinaryTree binTree = new BinaryTree();binTree.createBinTree();/* * 二叉树: * 1 * 2 3 * 4 5 6 7 * 8 9 */// nodeList中第0个索引处的值即为根节点Node root = nodeList.get(0);System.out.println("先序遍历:");preOrderTraverse(root);System.out.println();System.out.println("中序遍历:");inOrderTraverse(root);System.out.println();System.out.println("后序遍历:");postOrderTraverse(root);//权兴权意-2016.10.9System.out.println();System.out.println("计算结果:" + compDiameter(root));}}
- 算法之乐:一个算法解决3道经典二叉树面试题(深度、长度、直径)
- 二叉树的最大深度算法面试题-leetcode学习之旅(3)
- 微软四道经典算法面试题(附思路)
- 【面试题之算法部分】二叉树的遍历
- 九章算法面试题75 二叉树的最小深度
- 基于visual Studio2013解决面试题之0601二叉树深度
- 五道经典面试题
- 几道经典面试题
- 150道经典面试题
- 十道经典面试题
- Java29道经典面试题
- JS14道经典面试题
- 30道经典面试题
- 二叉树深度算法
- 面试题之求二叉树的深度
- 剑指offer面试题之求二叉树的深度
- 面试题之二叉树镜像(递归,非递归),深度
- 剑指offer面试题18判断一个二叉树是否包含另一个的递归算法
- Oracle 的四种连接-左外连接、右外连接、内连接、全连接
- 随笔记录-java并发编程
- java线程初探
- WebSocket 和 Socket 的区别
- 存储过程
- 算法之乐:一个算法解决3道经典二叉树面试题(深度、长度、直径)
- android volley封装及源码解析
- 2、lib7z-Memory从内存或网络解压数据(分析源码,修改源码)
- 【原创】有向图的搜索
- cocoa pods的安装与使用
- Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) C. Ray Tracing
- Linux内存管理之mmap详解
- Java 中 synchronized的用法详解(四种用法)
- 两个链表的第一个公共结点