树深度作为树最经常的考察的算法,值得引起我们的关注!而树深度问题往往与递归密切相关,相信再温习完《第八关青铜挑战笔记》后,树类型的递归问题已经可以迎刃而解,那么继续趁热打铁,一举拿下有关“树深度”问题及其变式应用!
方法一:递归
递归出口:树为空,树高度为0
递归逻辑:树的最大高度问题,就是求左右子树的最大高度+1
厘清逻辑,直接上代码!
public static int myMaxDepth_1(TreeNode root) {
if(root == null) return 0;
int leftDepth = myMaxDepth_1(root.left);
int rightDepth = myMaxDepth_1(root.right);
return Math.max(leftDepth, rightDepth) + 1;
}
方法二:层序遍历(模板)
逻辑:每遍历一层,树深度就加一层。
厘清逻辑,直接上代码!
public static int myMaxDepth_2(TreeNode root) {
if(root == null) return 0;
Queue queue = new LinkedList<>();
queue.offer(root);
int size = 0;
int depth = 0;
while(!queue.isEmpty()){
size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode t = queue.poll();
if(t.left != null) queue.offer(t.left);
if(t.right != null) queue.offer(t.right);
}
depth++;
}
return depth;
}
什么是平衡树?左子树和右子树的高度差不超过1(左右子树是指树全部左右子树)。
那么问题就在于,求解左子树高度和右子树高度,然后进行判断。
当左子树高度和右子树的高度差大于1,那么这个树不是平衡树返回-1;当左右子树高度差小于2,该树为平衡树,返回树高度为:左右子树最大高度+1;当树为空,则返回0。
递归出口:当树为空,则返回0;当左子树不平衡,返回-1;当右子树不平衡,返回-1。
递归逻辑:先判断左右子树是否平衡,当左右子树平衡且左右子树高度差小于2,该树为平衡树,返回树高度为:左右子树最大高度+1,否则不是平衡树,返回-1。
厘清思路,直接上代码!
public static boolean myIsBalanced_1(TreeNode root) {
return myRecur(root) != -1;
}
public static int myRecur(TreeNode root) {
if(root == null) return 0;
int left = myRecur(root.left);
if(left == -1) return -1;
int right = myRecur(root.right);
if(right == -1) return -1;
return Math.abs(left- right) < 2 ? Math.max(left, right) + 1 : -1;
}
根据树的最大深度,题目变式出了最小深度,该怎么处理?
方式一:层序遍历(模板)
遍历树的每一层,当该层第一次出现叶子节点的时候,该层深度就是树最小深度!厘清逻辑,直接上代码!
public static int myMinDepth_2(TreeNode root) {
if(root == null) return 0;
Queue queue = new LinkedList<>();
queue.offer(root);
int size = 0;
int depth = 0;
while(!queue.isEmpty()){
size = queue.size();
depth++;
for (int i = 0; i < size; i++) {
TreeNode t = queue.poll();
if(t.left != null) queue.offer(t.left);
if(t.right != null) queue.offer(t.right);
if(t.left == null && t.right == null) return depth;
}
}
return depth;
}
方式二:递归
递归出口:当树为空,树最小高度为0;
递归逻辑:当树节点的左孩子为空,树高度就是右子树高度+1;当树节点的右孩子为空,书高度就是左子树高度+1;当树节点左右孩子都不为空,树最小高度,就是左右子树的最小高度+1;(黑色加粗部分就是最小树高和最大树高问题的区别所在)
厘清逻辑,直接上代码!
public static int myMinDepth_1(TreeNode root) {
if(root == null) return 0;
if(root.left == null) return myMinDepth_1(root.right) + 1;
if(root.right == null) return myMinDepth_1(root.left) + 1;
return Math.min(myMinDepth_1(root.left), myMinDepth_1(root.right)) + 1;
}
N叉树的最大高度我们当然会按照两种方式进行思考,递归和层序遍历!
层序遍历,方法很简单,只需要统计遍历的几层即可!
递归方法,只需要记录当前节点的所有子树树高,然后选择最大的树高+1,就是当前N叉树最大高度。
递归出口:树为空,返回树高度为0;
递归逻辑:记录当前节点的所有子树树高,然后选择最大的树高+1
先按照这个思路写出代码!
public static int myMaxDepth_N(NTreeNode root) {
if(root == null) return 0;
ArrayList listDepth = new ArrayList<>();
for (NTreeNode child : root.children) {
listDepth.add(myMaxDepth_N(child));
}
return Collections.max(listDepth) + 1;
}
上面的代码有什么问题吗?当然有了!再for中child选择必须保证root.children不为空,而root.children为空意味着该节点为叶子节点,应该返回高度为1。于是,我们对上面代码进行修改:
public static int myMaxDepth_N(NTreeNode root) {
if(root == null) return 0;
if(root.children == null) return 1;
ArrayList listDepth = new ArrayList<>();
for (NTreeNode child : root.children) {
listDepth.add(myMaxDepth_N(child));
}
return Collections.max(listDepth) + 1;
}
这下没什么问题了吧,哈哈!别高兴太早,还有坑没填!坑在哪里?Collection.max()函数!试想,当root.children不为空但是root.children中没有任何元素,即是一个空列表的情况下,listDepth也必然是一个空列表!那么调用Collection.max()函数就会抛出异常!
怎么解决?增加条件呗!root.childern.isEmpty()这也表明没有孩子节点,为叶子节点,同时应该返回高度为1,于是继续修改代码!
public static int myMaxDepth_N(NTreeNode root) {
if(root == null) return 0;
if(root.children == null || root.children.isEmpty()) return 1;
ArrayList listDepth = new ArrayList<>();
for (NTreeNode child : root.children) {
listDepth.add(myMaxDepth_N(child));
}
return Collections.max(listDepth) + 1;
}
至此,N叉树的最大高度问题已经顺利解决了,我猜到这里聪明的你,已经能给自己出题了吧!
来吧!N叉树最小高度问题!怎么解决?答:两个思路,递归和层序遍历。
层序遍历,找到第一个叶子节点层,输出该层高度即可。
递归:递归出口:当树为空,树最小高度为0;当树节点的孩子都为空,该节点是叶子节点,树高度1;递归逻辑:当树节点有孩子节点的时候,树最小高度,就是孩子子树的最小高度+1;
代码留给你吧!加油!
OK,《算法通关村第八关——树经典算法白银挑战笔记》结束,喜欢的朋友三联加关注!关注鱼市带给你不一样的算法小感悟!(幻听)
再次,感谢鱼骨头教官的学习路线!鱼皮的宣传!小y的陪伴!ok,拜拜,第八关第三幕见!