【Hot100刷题计划】Day05 二叉树专题1(持续更新)

  • LeetCode Hot 100 是最常被考察的题目集合,涵盖了面试中常见的算法和数据结构问题。
  • 刷 Hot 100可以让你在有限的时间内集中精力解决最常考的问题。
  • 不仅要写出代码,还要理解问题的本质、优化解法和复杂度分析。
  • 遇到问题要多交流多求问多分享,“多折腾”能加深印象。

Day 4 二叉树专题训练

二叉树的题目,套路就几种,都刷一遍就有感觉了。递归,前序、中序、后序、层序遍历,以及在此基础上的变形。

在更新过程中发现前面做过的题会忘,所以可以4天一个周期。第4天做前面3天的题,补充笔记。

94. 二叉树的中序遍历

思路:

① 递归,深度优先遍历,左中右。

② 通过栈模拟递归的过程。

时间复杂度O(n),空间复杂度O(h).

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        self.res = []
        self.dfs(root)
        return self.res

    def dfs(self, node):
        if not node: return
        self.dfs(node.left)       # 递归,中序遍历,左 -> 中 -> 右
        self.res.append(node.val)
        self.dfs(node.right)    
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root: return []  # 二叉树为空,直接返回空列表
        stack = []              # 用于存储待处理的节点
        res = []                # 用于存储遍历结果
        cur = root              # 当前节点,初始化为根节点 root

        while cur or stack:     # 当前节点或者栈不为空,继续遍历
            if cur:
                stack.append(cur)  # 不为空,则将该节点压入栈中
                cur = cur.left     # 移动到其左子节点
            else:
                cur = stack.pop()    # 弹出栈顶元素,加入结果列表
                res.append(cur.val)
                cur = cur.right
        return res

102. 二叉树的层序遍历

思路: 使用一个队列,每次popleft遍历该层所有元素,有子节点则加入队列。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root: return []
        queue = collections.deque([root]) # 队列先进先出,用于BFS
        res = []
        while queue:                      # 队列有值,则继续
            temp = []
            for i in range(len(queue)):   # 每层所有节点遍历,加入左右子节点
                cur = queue.popleft()
                temp.append(cur.val)
                if cur.left: queue.append(cur.left)
                if cur.right: queue.append(cur.right)
            res.append(temp)
        return res

104. 二叉树的最大深度

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

思路:

① 递归,终止条件为到达叶子节点,则其深度为0. 递归遍历左子树和右子树,取最大值 + 1(节点本身)。

② 层序遍历,每遍历一层,给depth + 1. 时间复杂度O(n),空间复杂度O(m),取决于队列长度。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        if not root: return 0       # 终止条件,到达空节点,深度为0
        left = self.maxDepth(root.left)  # 递归遍历左子树,右子树
        right = self.maxDepth(root.right)
        return max(left, right)+1   # 子树最大深度加节点本身1
class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        if not root: return 0
        depth = 0
        queue = collections.deque([root])
        while queue:                        # 层序遍历
            depth += 1
            for i in range(len(queue)):
                cur = queue.popleft()       # 加入左右节点
                if cur.left: queue.append(cur.left)
                if cur.right: queue.append(cur.right)
        return depth

226. 翻转二叉树

思路:

① 递归。时间复杂度O(n),空间复杂度O(n).

② 层序遍历,对于每个节点都交换其左右节点。时间复杂度O(n),空间复杂度O(m).

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root: return None
        left = self.invertTree(root.left) # 翻转左子树
        right = self.invertTree(root.right) # 翻转右子树
        root.left, root.right = root.right, root.left # 交换左右节点
        return root

class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root: return None
        queue = collections.deque([root])

        while queue:  # 队列不为空,继续
            for i in range(len(queue)):
                cur = queue.popleft()    # 对于本层中的每个元素,翻转左右子树
                cur.left, cur.right = cur.right, cur.left
                if cur.left: queue.append(cur.left)
                if cur.right: queue.append(cur.right)
        return root

101. 对称二叉树

思路: 左右子节点存在且相等,且两子节点对称(左子节点的左半部分与右子节点的右半部分相等 and so on)

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        def isSame(left, right):  # 对称:两子树存在,且值相等,左右子树对称
            if not left and not right: return True
            if left and not right: return False
            if not left and right: return False
            if left.val != right.val: return False
            
            outside = isSame(left.left, right.right)
            inside = isSame(right.left, left.right)
            return outside and inside
        return isSame(root.left, root.right)
        

543. 二叉树的直径

思路: 借助最大深度思路,直径可以递归求深度的同时,更新为左子树和右子树深度和。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        self.ans = 0  # 初始化 ans
        self.depth(root)
        return self.ans - 1  # 直径是路径长度,路径长度 = 节点数 - 1

    def depth(self, root):
        if not root: return 0  # 空节点深度为 0
        left = self.depth(root.left)   # 左子树深度
        right = self.depth(root.right)  # 右子树深度
        self.ans = max(self.ans, left + right + 1)  # 更新最大直径
        return max(left, right) + 1  # 返回当前子树的深度
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值