代码随想录Day16:二叉树Part3

Leetcode 104. 二叉树的最大深度

讲解前:

这道题已经写了很多遍了利用dfs的遍历方法也非常简洁,用递归的思想去考虑,对于根节点的最大深度其实就是根节点本身的深度1加上左右子树其中的最大深度

class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        
        return max(1 + self.maxDepth(root.left), 1 + self.maxDepth(root.right))
讲解后:

看完了卡哥的讲解之后对这道题有了更深的理解,以及为什么我们要用后序遍历来解决这个问题,记住了一个知识点就是二叉树从根开始算的高度就是这个树的最大深度


Leetcode 559. N叉树的最大深度

class Solution:
    def maxDepth(self, root: 'Node') -> int:
        
        # base case
        if not root:
            return 0

        # have a max value to compare every children nodde 
        max_ = 0
        for node in root.children:
            max_ = max(max_, self.maxDepth(node))
        
        # deal with the current root 
        # post order traversal
        return 1 + max_

这道题的思路是一样的只不过在recursive case的时候,不能只比较左右子树的最大深度了,需要遍历所有的children node然后找出最大的深度node


Leetcode 111. 二叉树的最小深度

讲解前:

这道题昨天刚做过,不过是用的迭代法也就是层序遍历,就是说我们一层一层的找,每次找到新的层就先 + 1,但是当我们发现这层中有node没有左右子节点也就是说是一个leaf node的时候,就直接return 层数

这道题我想了好久,没办法想出一个比较合理的递归思路,我感觉我一直试着写也可能能过,但是没有一个自己非常明白的思路

讲解后:

好吧这道题大体的思路其实和最大深度是一样的,我陷入了一个错误的想法,还保留着利用层序遍历的思路想办法用dfs找到一个叶子节点之后直接返回类似有多少次recursive call的思路去找最小深度。其实正确的思路还是使用dfs的后序遍历,只是这里有一个小坑需要注意就是我们在最大深度的时候,遇到空的node我们可以直接return 0,然后呢我们每次recursive 之后处理的时候反正处理的是最大值,不用担心空节点的问题,但是对于最小深度,题目中要求的是从 leaf node到根节点的距离,当我们用min来处理左右节点的最小深度的时候,会把空节点的0考虑进去,可是这是不可以的,所以我们需要做一个小更改也就是当我们左右节点有一个为空的时候,我们不需要对其进行recursive call,直接return 有节点的最小深度就可以了

class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        # base case
        if not root:
            return 0
        
        # do the recursive call to get 
        # the left and right min depth
        left = self.minDepth(root.left)
        right = self.minDepth(root.right)

        # do the post order execute
        # if we miss one of the node
        # only return the one is not null
        if not root.left:
            return 1 + right
        elif not root.right:
            return 1 + left
        else:
            return 1 + min(left, right)

Leetcode 222. 完全二叉树节点数

讲解前:

这道题如果想过的话非常简单直接一个dfs遍历整棵树算出所有的节点数量就可以了

class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        res = 0

        def dfs(root):
            
            nonlocal res
            if not root:
                return
            
            res = res + 1
            dfs(root.left)
            dfs(root.right)
        
        dfs(root)
        return res

但是这道题已经说了这是一个完全二叉树,那么我们就知道,除了最后一层leaf node之外,别的层数都是满的也就是如果这个二叉树有n层,那总的节点数量应该是 2**(n-1)- 1 + leaf node

但是我想不出来如何在不遍历所有的节点的情况下找到树的深度以及遍历所有的叶子节点

讲解后:

看了卡哥的讲解之后恍然大悟,这道题其实关键不在于找到深度和最后一层的节点数量,而是明白当我们有了一个完全二叉树后,他有一个特性就是很好判断在树中存在的满二叉树

就如我图中画的一样,这时一个完全二叉树,当我们明白哪怕最后一层不满,也要从左往右添加了之后,我们明白,对于每一个节点,如果我们去计算他最长的左右节点长度,相当于一直找root.left.left.left.left 还有root.right.right.right 最后找到底了之后,如果长度一样,那么这个root一定是一个满二叉树的root,就如图中的圈起来的部分一样,这样以来我们其实可以在遍历的过程中,每一次都先检查当前的root是不是一个满二叉树的root,那么我们就可以直接算出来这个root下面的node的数量了,就是 2*depth - 1, 这样以来当树变得很大的时候,我们就可以减少很多遍历的node数量

class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:

        def count_node(root):

            # two base case
            # when we reach a null node
            if not root:
                return 0
            
            # check if the current root is a root of a 
            # full tree
            left_cur, left_length = root.left, 1
            right_cur, right_length = root.right, 1
            while left_cur:
                left_length += 1
                left_cur = left_cur.left

            while right_cur:
                right_length += 1
                right_cur = right_cur.right
            
            # if it is a full tree, get its node count
            if left_length == right_length:
                return 2 ** left_length - 1
            
            # now do the recursive case
            left_count = count_node(root.left)
            right_count = count_node(root.right)

            # get the solution as left count and right count and root
            return left_count + right_count + 1
        
        return count_node(root)

  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值