随想录算法训练营第十五天|二叉树的层序遍历,学会一套代码你可以解决十道leetcode!!

102.二叉树的层序遍历

层序遍历一个二叉树,即从左到右一层一层的去遍历二叉树,需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑;而用栈先进后出,适合模拟深度优先遍历也就是递归的逻辑。这种层序遍历方式就是图论中的广度优先遍历,只不过我们应用在二叉树上。

法一:迭代法

# 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 []
        que = deque([root])
        # que.append(root)
        res = []
        while que:
            size = len(que)
            vector = []
            while size > 0:
                node = que.popleft()
                vector.append(node.val)
                if node.left: 
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
                size -= 1
            res.append(vector)
        
        return res

法二:递归

# 递归法
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        res = []
        def helper(root, depth):
            if not root: return []
            if len(res) == depth: res.append([]) # start the current depth
            res[depth].append(root.val) # fulfil the current depth
            if  root.left: helper(root.left, depth + 1) # process child nodes for the next depth
            if  root.right: helper(root.right, depth + 1)
        helper(root, 0)
        return res

能理解,但自己想不到

    1. 二叉树的层序遍历 II
      自底向上从左至右返回层序遍历的值,则只需返回上述code里的 res[::-1] 即可
    1. 二叉树的右视图
      给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
# 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 rightSideView(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []
        res = []
        que = deque([root])
        while que:
            size = len(que)
            vector = []
            for _ in range(size):
                node = que.popleft()
                vector.append(node.val)
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
            res.append(vector[-1])  # 只需将这一步改为添加每层遍历得到的数组最右边的值到res数组里
        return res
    1. 二叉树的层平均值
# 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 averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
        if not root:
            return []
        res = []
        que = deque([root])
        while que:
            size = len(que)
            # vector = []
            total = 0
            for _ in range(size):
                node = que.popleft()
                total += node.val # 将数组改为求和,不改也可以,下面res.append(mean(vector)即可
                # vector.append(node.val)
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
            res.append(total / size)  # 求每层结点值的平均值即可
        return res
    1. N 叉树的层序遍历

给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。

"""
# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""
class Solution:
    def levelOrder(self, root: 'Node') -> List[List[int]]:
        if not root:
            return []
        res = []
        que = deque([root])
        while que:
            size = len(que)
            vector = []
            for _ in range(size):
                node = que.popleft()
                vector.append(node.val)
                if node.children:
                    que.extend(node.children)  # 唯一的区别就是二叉树分左右孩子,而N叉树用children,可能为null,可能为一个列表 
            res.append(vector)
        return res  
    1. 在每个树行中找最大值

给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

# 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 largestValues(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []
        res = []
        que = deque([root])
        while que:
            size = len(que)
            vector = []
            for _ in range(size):
                node = que.popleft()
                vector.append(node.val)
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
            res.append(max(vector))  # 添加最大值即可
        return res
    1. 填充每个节点的下一个右侧节点指针
      给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
  struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node

此题不需要额外的数组(类似上述代码里res和vector)存储结果,直接在root上做改变的,返回root即可

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

class Solution:
    def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
        if not root:
            return None
 		
 		que = deque([root])
        while que:
            size = len(que)
            for i in range(size):
                node = que.popleft()
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
                if i == size - 1:
                    break
                node.next = que[0]  # 弹出node,此时que[0]即为node的右兄弟                  
        return root
    1. 填充每个节点的下一个右侧节点指针 II
      和上一题解法一模一样,无所谓是二叉树还是完美二叉树
    1. 二叉树的最大深度
      给定一个二叉树,找出其最大深度。
      二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
      说明: 叶子节点是指没有子节点的节点。
# 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
        count = 0  # 记录层数
        que = deque([root])
        while que:
            size = len(que)
            # vector = []
            for i in range(size):
                node = que.popleft()
                # vector.append(node)
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
            count += 1       
        return count
    1. 二叉树的最小深度
      给定一个二叉树,找出其最小深度。
      最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
# 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 minDepth(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        count = 0  # 记录层数
        que = deque([root])
        while que:
            size = len(que)
            # vector = []
            for i in range(size):
                node = que.popleft()
                # vector.append(node)
                if (not node.left) and (not node.right):
                    return count + 1  # 一旦我遍历到的node无左右孩子,直接返回 count+1
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
                
            count += 1       
        return count

226. 翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

法一:层序遍历时交换左右指针

# 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
        que = deque([root])
        while que:
            size = len(que)
            for _ in range(size):
                node = que.popleft()
                node.left, node.right = node.right, node.left # 在这里交换左右指针即可,其他同层序遍历
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
        return root 

法二:递归

# 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 root
        root.left, root.right = root.right, root.left  # 中
        self.invertTree(root.left)  # 左
        self.invertTree(root.right)  # 右        
        return root

# 后序
# self.invertTree(root.left)  # 左
# self.invertTree(root.right)  # 右     
# root.left, root.right = root.right, root.left  # 中

# 中序
class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root:
            return root
        
        self.invertTree(root.left)  # 左
        root.left, root.right = root.right, root.left  # 中
        self.invertTree(root.left)  # 右  # 因为在递归左子树时已经交换过左右了,此时递归的右子树就变成交换之前的左子树了
        # 所以就要交换之前的右子树,即现在的左子树       
        return root   

法三:前序遍历用的迭代法 用栈模拟

class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return root
        st = []
        st.append(root)
        while st:
            node = st.pop()
            node.left, node.right = node.right, node.left #中
            if node.right:
                st.append(node.right) #右
            if node.left:
                st.append(node.left) #左
        return root

101. 对称二叉树

这道题理解code略有点难,需要好好推一推

# 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:
        if not root:
            return True
        return self.compare(root.left, root.right) 
        # 传入参数是根结点的左右子树,因为比较的是左右子树是否可以互相翻转

    def compare(self, left, right):
        # 首先排除空节点的情况
        if left == None and right != None: return False
        elif left != None and right == None: return False
        elif left == None and right == None: return True
        # 排除非空 但左右值不等
        elif left.val != right.val: return False

        #此时就是:左右节点都不为空,且数值相同的情况
        #此时才做递归,做下一层的判断
        outside = self.compare(left.left, right.right) #左子树:左、 右子树:右
        inside = self.compare(left.right, right.left) #左子树:右、 右子树:左
        isSame = outside and inside #左子树:中、 右子树:中 (逻辑处理)
        return isSame
  • 也可以使用迭代法
    在这里插入图片描述
# 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

import collections
class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if not root:
            return True
        queue = collections.deque()
        queue.append(root.left) #将左子树头结点加入队列
        queue.append(root.right) #将右子树头结点加入队列
        while queue: #接下来就要判断这这两个树是否相互翻转
            leftNode = queue.popleft()
            rightNode = queue.popleft()
            if not leftNode and not rightNode: #左节点为空、右节点为空,此时说明是对称的
                continue
            
            #左右一个节点不为空,或者都不为空但数值不相同,返回false
            if not leftNode or not rightNode or leftNode.val != rightNode.val:
                return False
            queue.append(leftNode.left) #加入左节点左孩子
            queue.append(rightNode.right) #加入右节点右孩子
            queue.append(leftNode.right) #加入左节点右孩子
            queue.append(rightNode.left) #加入右节点左孩子
        return True
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值