Day14 力扣二叉树 : 104.二叉树的最大深度 (优先掌握递归)| 111.二叉树的最小深度 (优先掌握递归)|222.完全二叉树的节点个数(优先掌握递归)

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;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值