《剑指offer》刷题——【面试中的各项能力】面试题55:二叉树的深度(java实现)
(一) 题目一:二叉树的深度
一、题目描述
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长
路径的长度为树的深度。
二、题目分析
- 若一棵树只有一个节点,深度=1;
- 若根节点只有左子树没有右子树,深度=左子树的深度+1
- 若根节点只有右子树没有左子树,深度=右子树的深度+1
- 若根节点既有左子树又有右子树,深度=max(左子树深度,右子树深度)+1
三、代码实现
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public int TreeDepth(TreeNode root) {
//输入有误
if(root==null){
return 0;
}
//递归左子树深度
int left = TreeDepth(root.left);
//递归右子树深度
int right = TreeDepth(root.right);
//返回左子树或右子树深度较大的一个加一
return (left > right)? (left + 1):(right + 1);
}
}
(二)题目二:平衡二叉树
一、题目描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树。如果某二叉树中**任意节点**左、右子树的深度相差不超过1,
那么他就是一棵二叉树。
二、题目分析
方法一:递归——重复遍历
- 遍历树的每一个节点时,调用TreeDepth得到每个节点的左、右子树的深度
- 若每个节点的左、右子树的深度相差不超过1,即为平衡二叉树
public class Solution {
public boolean IsBalanced_Solution(TreeNode root) {
//输入有误
if(root==null){
return true;
}
//左子树的深度
int left = TreeDepth(root.left);
//右子树的深度
int right = TreeDepth(root.right);
//左右子树差
int diff = left - right;
//深度差超过1,则不是平衡二叉树
if(diff>1 || diff<-1){
return false;
}
//深度差不超过1,则遍历左子节点 右子节点
return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
}
/**
*求树的深度
*/
public int TreeDepth(TreeNode root) {
//输入有误
if(root==null){
return 0;
}
//递归左子树深度
int left = TreeDepth(root.left);
//递归右子树深度
int right = TreeDepth(root.right);
//返回左子树或右子树深度较大的一个加一
return (left > right)? (left + 1):(right + 1);
}
}
- 存在问题:重复遍历节点多次,时间效率不高
方法二:每个节点只遍历一次
- 后序遍历(遍历到根节点时,已经遍历完左右节点了)
- 遍历某个节点的左、右子节点后,根据左右深度,确定是否为平衡,并得到当前节点的深度
- 当最后遍历到树的根节点时,也就能判断整棵树是不是平衡二叉树
public class Solution {
public boolean IsBalanced_Solution(TreeNode root) {
int depth = 0;//树的深度
return IsBalanced(root, depth);
}
/**
*判断二叉树是否平衡,并同时记录深度
*/
public boolean IsBalanced(TreeNode root , int depth){
//空树
if(root==null){
depth = 0;
return true;
}
int left=0;
int right=0;//左右子树深度
//如果左右节点平衡
if(IsBalanced(root.left,left) && IsBalanced(root.right, right)){
//求左右子树深度差
int diff = left-right;
if(diff<=1 && diff>=-1){
//当前节点的深度为左右深度大的一个的深度+1
depth = 1 +(left>right ? left:right);
return true;
}
}
//若左右节点不平衡,则不是平衡二叉树
return false;
}
}
上述实现存在问题及解决方案:=
在c或c++中我们可以给递归的子过程中传入左右子树的高度的指针,当子过程回溯时,我们就可以
拿到改变后的值,而这种效果得益于指针的优势。而在Java中只有值传递,子过程改变的值,在父
过程中是看不见,子过程改变仅仅是实参的副本,实参本身是不发生变化的。所以我们要定义一对
象来持有深度值,这样子过程通过引用修改对象的成员变量时,父过程中的引用由于与实参(该引
用)的副本指向同一个对象,故而是可见的。
public class Solution {
/**
* 定义一个深度对象,递归子过程通过引用、修改对象的成员变量时,
父过程中的引用由于与实参的副本指向同一个对象,子过程改变父过程可以看见
*/
public static class DepthHolder{
int depth=0;
}
public boolean IsBalanced_Solution(TreeNode root) {
//空树
if(root==null){
return true;
}
//实例化深度对象
DepthHolder depthHolder = new DepthHolder();
return IsBalanced(root, depthHolder);
}
/**
*判断二叉树是否平衡,并同时记录深度
*/
public boolean IsBalanced(TreeNode root , DepthHolder depthHolder){
//空树
if(root==null){
depthHolder.depth = 0;
return true;
}
//实例化深度对象
DepthHolder leftDepth= new DepthHolder();
//实例化深度对象
DepthHolder rightDepth = new DepthHolder();
int right=0;//左右子树深度
//如果左右节点平衡
if(IsBalanced(root.left,leftDepth) && IsBalanced(root.right, rightDepth)){
//求左右子树深度差
int diff = leftDepth.depth - rightDepth.depth;
if(diff<=1 && diff>=-1){
//当前节点的深度为左右深度大的一个的深度+1
depthHolder.depth = 1 +(leftDepth.depth>rightDepth.depth ? leftDepth.depth:rightDepth.depth);
return true;
}
}
//若左右节点不平衡,则不是平衡二叉树
return false;
}
}