Day14 力扣二叉树 : 104.二叉树的最大深度 (优先掌握递归)| 111.二叉树的最小深度 (优先掌握递归)|222.完全二叉树的节点个数(优先掌握递归)
104.二叉树的最大深度 (优先掌握递归)
什么是深度,什么是高度,如何求深度,如何求高度,这里有关系到二叉树的遍历方式。
大家 要先看视频讲解,就知道以上我说的内容了,很多录友刷过这道题,但理解的还不够。
题目链接/文章讲解/视频讲解:
https://programmercarl.com/0104.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%A4%A7%E6%B7%B1%E5%BA%A6.html
第一印象:
这道题在层序遍历那里做过了,直接看视频理解一下深度、高度。
看完题解的思路:
层序遍历的时候做这道题,就是一层一层遍历,遍历一层深度depth就+1。 但在这个篇章中,希望我们理解的是:
高度: 节点和叶子节点的距离
深度: 节点和根节点的距离
求深度就是从上往下一层层去看,求高度是从下往上一层层去看。那么求高度就是一个有些别扭的过程,它和正常地去遍历一个树是不一样的。
所以求高度的时候就需要后序遍历,因为左右根的顺序,可以算出根的高度,然后返回给上一层节点。
那么为什么求最大深度的题,要去计算高度呢?因为最大深度就是根节点的高度。
实现上的困难:
没有困难。
感悟:
后序遍历感觉常用于返回值和左右子树有关系的情况,比如这道题需要根据左右子树的高度返回自己的高度。
代码:
class Solution {
public int maxDepth(TreeNode root) {
return depth(root);
}
private int depth(TreeNode node) {
if (node == null) return 0;
//后序遍历
int left = maxDepth(node.left);
int right = maxDepth(node.right);
//用左右子树高度算自己的高度
int height = 1 + Math.max(left, right);
return height;
}
}
559.n叉树的最大深度
这道题是推荐的相关题目
第一印象:
就是把找左右节点里最大那个变成了 找List里最大那个而已,直接做对!!!
代码:
class Solution {
public int maxDepth(Node root) {
return depth(root);
}
private int depth(Node node) {
if (node == null) return 0;
int maxChild = 0;
for (Node child : node.children) {
int dep = depth(child);
maxChild = Math.max(maxChild, dep);
}
return 1 + maxChild;
}
}
111.二叉树的最小深度 (优先掌握递归)
先看视频讲解,和最大深度 看似差不多,其实 差距还挺大,有坑。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0111.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%B0%8F%E6%B7%B1%E5%BA%A6.html
第一印象:
在层序遍历的时候也做过,但是不会递归的,直接看视频了。
看完题解的思路:
整体代码和最大深度是一样的,但是有一个误区,最小深度是对于叶子节点来说的,而不是对于NULL节点来说的。
所以在返回深度的时候要注意这个问题。
而在层序遍历的方法中,找的是第一个叶子节点,也就是左右孩子都是null的节点。在这个过程中不断的记录深度。找到叶子节点就直接返回深度就行了。
实现中的困难:
实现起来没有困难,只需要滤清思路。
我一开始不理解为什么每个 if 的判断条件是一个孩子是不是空,那要是两个都是空呢?
如果左右孩子都是空的时候,left就是0,right就是0,返回较小的并+1
如果有一个孩子是空,left就是0,right比如是1,就不能返回较小的,所以才需要那两个 if 去处理。
感悟:
两个if的判断条件也可以是
if (left == 0) {
return right + 1;
}
if (right == 0) {
return left + 1;
}
代码:
class Solution {
public int minDepth(TreeNode root) {
return getMinDepth(root);
}
private int getMinDepth(TreeNode node) {
if (node == null) return 0;
int left = getMinDepth(node.left);
int right = getMinDepth(node.right);
if (node.left == null) {
return right + 1;
}
if (node.right == null) {
return left + 1;
}
return 1 + Math.min(left, right);
}
}
222.完全二叉树的节点个数(优先掌握递归)
需要了解,普通二叉树 怎么求,完全二叉树又怎么求
题目链接/文章讲解/视频讲解:https://programmercarl.com/0222.%E5%AE%8C%E5%85%A8%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E8%8A%82%E7%82%B9%E4%B8%AA%E6%95%B0.html
第一印象:
想层序遍历去记录数量,有点太简单了,直接看题解的递归。
看完题解的思路:
如果把他当做普通的二叉树去后序遍历记录数量比较简单,学习一下如何利用完全二叉树的性质去计算。
2^n - 1 可以计算出一个高度为 n 的满二叉树的节点数量。利用这个就可以方便计算,少遍历一些节点。思路就是,如果一个节点为根的二叉树是满二叉树就直接计算,不是的话就去看他的左右孩子是不是,至少叶子节点一定是满二叉树。
我一开始不理解的地方是,他的终止条件有两条,除了常见的 if (root == null) return 0;
还有下面这一大段思路的实现,我不理解这个思路的实现为什么放在终止条件里?
我还觉得这段代码让if (root == null) return 0;
失效了,因为遍历到叶子节点的时候,他一定是进入这些代码里面,根本没机会再递归叶子节点的左右孩子,去执行if (root == null) return 0;
。
//如果当前节点是满二叉树的根,直接计算
//至少叶子节点一定是
int leftdepth = 0;
int rightdepth = 0;
TreeNode left = root.left;
TreeNode right = root.right;
//一直去找最左面的
while (left != null) {
left = left.left;
leftdepth++;
}
//一直去找最右面的
while (right != null) {
right = right.right;
rightdepth++;
}
//至少叶子节点一定是,会返回1
if (leftdepth == rightdepth) return (2<<leftdepth) - 1;
后来想明白了,对于一个只有一个右孩子的节点来说,它不是满二叉树,就会递归它的左,递归它的右。
递归它的左节点的时候,就会执行if (root == null) return 0;
,而递归它的右节点,就会执行上面的代码。
所以考虑终止条件的时候,要想想 null 、叶子节点 和 这种一个孩子的节点情况,就比较清晰,因为它们都是终止时候的情况。
实现的困难
这个也是一道思路清晰就不难实现的题目。
感悟:
所以考虑终止条件的时候,要想想 null 、叶子节点 和 这种一个孩子的节点情况,就比较清晰,因为它们都是终止时候的情况。
代码:
class Solution {
public int countNodes(TreeNode root) {
//如果遍历到了空节点
if (root == null) return 0;
//如果当前节点是满二叉树的根,直接计算
//至少叶子节点一定是
int leftdepth = 0;
int rightdepth = 0;
TreeNode left = root.left;
TreeNode right = root.right;
//一直去找最左面的
while (left != null) {
left = left.left;
leftdepth++;
}
//一直去找最右面的
while (right != null) {
right = right.right;
rightdepth++;
}
//至少叶子节点一定是,会返回1
if (leftdepth == rightdepth) return (2<<leftdepth) - 1;
//如果当前节点不是蛮二叉树的根,去看他的左右孩子
int leftnum = countNodes(root.left);
int rigthnum = countNodes(root.right);
int result = leftnum + rigthnum + 1;
return result;
}
}