代码随想录27期|Python|Day15|二叉树|层序遍历|对称二叉树|翻转二叉树

本文图片来源:代码随想录

层序遍历(图论中的广度优先遍历)

这一部分有10道题,全部可以套用相同的层序遍历方法,但是需要在每一层进行处理或者修改。

102. 二叉树的层序遍历 - 力扣(LeetCode)

层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。

需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。

 队列长度法

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        # 判断是不是空二叉树
        if not root:
            return []
        # 先把根节点放入队列
        queue = collections.deque([root])
        res = []
        # 然后逐层放入队列再弹出
        while queue:
            # 每层储存在level数组里
            level = []
            for _ in range(len(queue)):
                # 弹出根节点,存值
                cur = queue.popleft()
                level.append(cur.val)
                # 队列添加左右节点
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 每层走完
            res.append(level)
        return res

递归法

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        # 递归法
        levels = []
        self.helper(root, 0, levels)
        return levels

    def helper(self, node, level, levels):
        # 退出条件
        if not node:
            return
        # 当层数和levels的长度相等的时候,也就是满二叉树的时候,需要再加上一个新的层
        if len(levels) == level:
            levels.append([])
        levels[level].append(node.val)
        self.helper(node.left, level + 1, levels)
        self.helper(node.right, level + 1, levels)

107. 二叉树的层序遍历 II - 力扣(LeetCode)

只需要倒序输出即可,代码和上面102保持一致。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def levelOrderBottom(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if not root:
            return []
        queue = collections.deque([root])
        res = []
        while queue:
            levels = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                levels.append(cur.val)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            res.append(levels)
        # 反向输出即可
        return res[::-1]

199. 二叉树的右视图 - 力扣(LeetCode)

只需要每次把levels最后一个也就是最右侧的节点赋值给res即可。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def rightSideView(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if not root:
            return []
        res = []
        queue = collections.deque([root])
        while queue:
            levels = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                levels.append(cur.val)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 只需要每次把levels最后一个也就是左右侧的节点赋值给res即可
            res.append(levels[-1])
        return res

637. 二叉树的层平均值 - 力扣(LeetCode)

只需要在求出每层的基础上求平均即可。

注意作除法之前需要类型转换为float。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def averageOfLevels(self, root):
        """
        :type root: TreeNode
        :rtype: List[float]
        """
        if not root:
            return []
        res = []
        queue = collections.deque([root])
        while queue:
            levels = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                levels.append(cur.val)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 需要强制类型转换为浮点数
            sum_ = float(sum(levels))
            len_ = float(len(levels))
            avg = sum_ / len_
            res.append(avg)
        return res

429. N 叉树的层序遍历 - 力扣(LeetCode)

只需要把children列表里的元素按照顺序取出即可。

"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution(object):
    def levelOrder(self, root):
        """
        :type root: Node
        :rtype: List[List[int]]
        """
        if not root:
            return []
        res = []
        queue = collections.deque([root])
        while queue:
            levels = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                levels.append(cur.val)
                # children按列表储存child
                for child in cur.children:
                    queue.append(child)
            res.append(levels)
        return res

 515. 在每个树行中找最大值 - 力扣(LeetCode)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def largestValues(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if not root:
            return []
        res = []
        queue = collections.deque([root])
        while queue:
            level = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                level.append(cur.val)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 每层最大值赋值给res
            res.append(max(level))
        return res

116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode)

"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=0, left=None, right=None, next=None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""

class Solution(object):
    def connect(self, root):
        """
        :type root: Node
        :rtype: Node
        """
        if not root:
            return root  # 注意这一题的返回值是根节点地址,相当于只在原链表的基础上做修改
        queue = collections.deque([root])
        while queue:
            level = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                # queue的下一个值其实就是next需要指向的地址
                # if _ < len(queue) - 1:
                #   cur.next = queue[0]
                level.append(cur)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 在每一层遍历
            for i in range(len(level) - 1):
                level[i].next = level[i + 1]
        return root

 117. 填充每个节点的下一个右侧节点指针 II - 力扣(LeetCode)

"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=0, left=None, right=None, next=None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""

class Solution(object):
    def connect(self, root):
        """
        :type root: Node
        :rtype: Node
        """
        if not root:
            return root  # 注意这一题的返回值是根节点地址,相当于只在原链表的基础上做修改
        queue = collections.deque([root])
        while queue:
            level = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                # queue的下一个值其实就是next需要指向的地址
                # if _ < len(queue) - 1:
                #   cur.next = queue[0]
                level.append(cur)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 在每一层遍历
            for i in range(len(level) - 1):
                level[i].next = level[i + 1]
        return root    

104. 二叉树的最大深度 - 力扣(LeetCode)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        # 广度优先
        if not root:
            return 0
        cnt = 0
        queue = collections.deque([root])
        while queue:
            # 构造一层的队列
            for _ in range(len(queue)):
                cur = queue.popleft()
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 构造完加一
            cnt += 1
        return cnt

        # 递归法
        if not root:
            return 0
        else:
            left_height = self.maxDepth(root.left)
            right_height = self.maxDepth(root.right)
        return max(left_height, right_height) + 1

        # 精简递归
        return 0 if not root else max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1

111. 二叉树的最小深度 - 力扣(LeetCode)

找到第一个叶子节点就退出while。这里用到了flag标记。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def minDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        # 广度优先
        if not root:
            return 0
        cnt = 0
        queue = collections.deque([root])
        flag = 0
        while queue:
            # 构造一层的队列
            for _ in range(len(queue)):
                cur = queue.popleft()
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
                if not (cur.left or cur.right):
                    flag = 1
            cnt += 1
            # 构造完加一
            if flag:
                break
        return cnt

226. 翻转二叉树 - 力扣(LeetCode)

深度遍历

omg!baseline只需要上面的套模板即可实现!!这不神奇吗??!!

根据顺序做具体的微调

前序/后续

只需要在原来代码的基础上加上子节点的交换过程即可。

递归法里的写法:

root.left, root.right = root.right, root.left

 迭代法里的写法:

node = stack.pop()   
node.left, node.right = node.right, node.left

中序

需要注意中序在执行完交换之后原来的左节点是右节点,但是right指针指向的是原left节点,所以需要在两次递归的时候都要指向left

self.invertTree(root.left)
root.left, root.right = root.right, root.left
selfinvertTree(root.left)

广度遍历(层序遍历)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def invertTree(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        # 层序遍历
        if not root:
            return root
        queue = collections.deque([root])
        while queue:
            for _ in range(len(queue)):
                node = queue.popleft()
                # 对于取出队列里的每一个节点交换左右子节点
                node.left, node.right = node.right, node.left
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return root

101. 对称二叉树 - 力扣(LeetCode)

递归

 思路是分别比较两个子树的内侧和外侧,然后将结果取交集返回中间节点。所以确定便利的顺序一定是后序遍历(最后一个确定中间节点)。

因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
    # 递归法
        if not root:
            return True
        return self.compare(root.left, root.right)
    def compare(self, left, right):
        """
        左----右----result
        空    空     True
        空    有     False
        有    空     False
        有 != 有     False
        有 == 有     True
        """
        if left == None and right == None:
            return True
        elif left == None and right != None:
            return False
        elif left != None and right == None:
            return False
        elif left.val != right.val:
            return False
        else:  # 此时已经说明left == right,需要再判断他们的子节点
            outside = self.compare(left.left, right.right)  # 外侧子节点
            inside = self.compare(left.right, right.left)  # 内侧子节点
        is_same = outside and inside  # 求交集
        return is_same

 层序遍历

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        # 层次法
        queue = collections.deque([root])
        while queue:
            level_val = []  # 只需要保存值
            for _ in range(len(queue)):
                node = queue.popleft()
                if node:
                    level_val.append(node.val)
                    queue.append(node.left)
                    queue.append(node.right)
                else:  # 空节点赋值为None
                    level_val.append(None)
            if level_val != level_val[::-1]:  # 倒序比较数组
                return False
        return True

队列或栈

关键:成对取出外侧和内侧节点进行比较。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        # 栈或队列(队列只要把栈改成队列,pop搞成popleft就可以了)
        if not root:
            return True
        stack = []
        stack.append(root.left)
        stack.append(root.right)
        while stack:
            left = stack.pop()
            right = stack.pop()
            if left == None and right == None:
                continue  # 注意在while里需要continue
            if left == None or right == None or left.val != right.val:
                return False
            stack.append(left.left)
            stack.append(right.right)
            stack.append(left.right)
            stack.append(right.left)
        return True

2个相关题

100. 相同的树 - 力扣(LeetCode)

两个树,如果采用层序遍历的方法最好把重复部分封装成一个整体的函数。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isSameTree(self, p, q):
        """
        :type p: TreeNode
        :type q: TreeNode
        :rtype: bool
        """
        # 层次法
        queue1 = collections.deque([p])
        queue2 = collections.deque([q])
        while queue1 and queue2:
            if len(queue1) != len(queue2):
                return False
            level1 = self.get_level(queue1)
            level2 = self.get_level(queue2)
            if level1 != level2:
                return False
        return True

    def get_level(self, queue):
        level_val = []
        for _ in range(len(queue)):
            node = queue.popleft()
            if node:
                level_val.append(node.val)
                queue.append(node.left)
                queue.append(node.right)
            else:
                level_val.append(None)
        return level_val

 572. 另一棵树的子树 - 力扣(LeetCode)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isSubtree(self, root, subRoot):
        """
        :type root: TreeNode
        :type subRoot: TreeNode
        :rtype: bool
        """
        # 深度遍历+递归
        if not root:
            return False
        
        return self.check_is_same(root, subRoot) or self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)

    def check_is_same(self, root, subroot):
        if root == None and subroot == None:
            return True
        elif root == None or subroot == None or root.val != subroot.val:
            return False
        return self.check_is_same(root.left, subroot.left) and self.check_is_same(root.right, subroot.right)

第15天完结🎉

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值