Leetcode刷题(29)二叉树专题:求树的深度(递归、深度优先搜索、宽度优先搜索)

题目

104. 二叉树的最大深度

在这里插入图片描述

难度:简单
分析:最简单的方法是使用递归,代码最少,速度也不慢;同时可以单独维持一个栈或是队列,使用深度优先搜索(DFS)或是宽度优先搜索(BFS)来得出答案。

不管是使用哪种方法,所有节点都必须被遍历,才能获得答案。

解法一:借助队列,宽度优先搜索

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
    	# 使用队列
        from collections import deque
        
        if not root:
            return 0
        
        depth = 0
        my_que = deque()
        my_que.append(root)
        
        while my_que:
            size = len(my_que)
            depth += 1
            for _ in range(size):
                node = my_que.popleft()
                if node.left: my_que.append(node.left)
                if node.right: my_que.append(node.right)
        
        return depth

运行结果:

在这里插入图片描述

解法二:借助栈,深度优先搜索

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
    	if not root:
            return 0
        depth = 0
        stack = [(root, 1)]
        
        while stack:
            node, level = stack.pop()
            if node:
                if not node.left and not node.right: # 叶节点
                    depth = max(depth, level)
                    continue
            
                stack.append((node.right, level +1))
                stack.append((node.left, level +1))
                
        return depth

运行结果:

在这里插入图片描述

分析:

  1. 栈必须要把每一层的层次信息存储,不然无法区分同一层的节点;
  2. 更新答案深度信息的时候,不一定要判断是否叶节点。下面是深度优先的另一种解法。

不判断叶节点的解法:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
    	if not root:
            return 0
        depth = 0
        stack = [(root, 1)]
        
        while stack:
            node, level = stack.pop()
            if node:
                depth = max(depth, level)
                stack.append((node.right, level +1))
                stack.append((node.left, level +1))
                
        return depth

运行结果:

在这里插入图片描述
在这里插入图片描述

分析:

从运行时间来看,对于题目中给定的测试集,判断叶节点的方法更优。

假设被测试的树是一棵满二叉树,所有叶节点(假设为第n层)的左右子树节点不需要进栈,省去了 2 n 2^n 2n个节点的进栈和判断,同时省去了 2 n − 1 2^{n} - 1 2n1次更新depth;而仅是增加了判断叶节点次数是 2 n − 1 2^n -1 2n1

因此,判断叶节点的方法更快便是理所当然了。

解法三:基于递归自上而下的求解

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
    	def depthCal(root, depth):
            nonlocal ans
            if not root:
                return
            if not root.left and not root.right: # 叶节点
                ans = max(ans, depth)
                
            depthCal(root.left, depth + 1)
            depthCal(root.right, depth + 1)
        ans = 0  
        depthCal(root, 1)
        
        return ans

运行结果:

在这里插入图片描述
在这里插入图片描述

分析:

基于递归编写的解法,一般均需要单独定义一个子函数来完成递归,这样的目的是为了方便使用存储答案的ans变量,把答案传递出来。

解法四:基于递归自下而上的方法

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        # 递归,自下向上
        if not root:
            return 0
        
        left_depth = self.maxDepth(root.left)
        right_depth = self.maxDepth(root.right)
        
        return max(left_depth, right_depth) + 1

运行效果:

在这里插入图片描述
在这里插入图片描述

总结:

对于树的问题,使用递归是最简单且最直接的方式。

不过,使用迭代的方法,虽然代码变长了,但是运行时间有可能变短!

应该特别注意的是,我们自己维护一个栈或是队列时,叶子节点一定不要进栈或是进队列。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值