代码随想录算法训练营0522| 层序遍历 10 、226.翻转二叉树 、101.对称二叉树 2

题也太多了……

DFS和BFS的区别

1、深度优先搜索(DFS):

  • 遍历方式: 从一个子树深入到另一个子树,从底层往上遍历,直到遍历完整个树。
  • 实现方式: 通常使用递归(如前序遍历、中序遍历、后序遍历)或者使用
  • 特点: DFS会沿着树的一个分支尽可能深入,然后再回溯到上一层继续遍历其他分支。

2、广度优先搜索(BFS):

  • 遍历方式: 一层一层地遍历,从根节点开始,先遍历当前层的所有节点,再遍历下一层的节点。
  • 实现方式: 通常使用队列
  • 特点: BFS会首先访问离根节点最近的节点,然后逐层向下遍历

因为TreeNode的存储方式是从上到下从左到右存储,为空的存为Null。一般是链表形式存储,一个节点存三个数据[val, left指针, right指针] 。

从底层回溯刚好用栈(先进后出),层序则用队列(先进先出)

层序遍历  10 (BFS)

from collections import deque

# 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
            return []
        deque = collections.deque([root])#根节点
        res = []
        while deque:#deque不为空的时候(还有节点),一直循环
            level = []#用于存储本层的节点的值
            for i in range(len(deque)):#当层队列的长度,循环一次后,队列长度会变成下一层队列的长度
                cur = deque.popleft()
                level.append(cur.val)
## 判断左右节点不为空就放入deque,别忘了!
                if cur.left:#左节点不为空,就把左节点加入队列
                    deque.append(cur.left)
                if cur.right:
                    deque.append(cur.right)
            res.append(level)
        return res

和链表的思维方式基本一样,访问是以头节点开始。

递归写法

# 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 levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
        levels = []
        self.helper(root,0,levels)#修改levels对象,在类内修改,因此helper函数不需要return
        return levels[::-1]#倒序输出

    # helper 是类内函数,所以需要加一个self
    def helper(self,node,level,levels):#节点,层序号,数据存储容器(输入参数)
        if not node:#终止条件
            return 

        #每一层递归要做的事
        if len(levels) == level:#在当前层次,加一个空列表用于append
            levels.append([])

        levels[level].append(node.val)#存储当前节点的值
        self.helper(node.left, level+1, levels)#本节点的左节点(下一层)
        self.helper(node.right, level+1, levels)#本节点的右节点(下一层)

依然是递归三要素:输入输出、终止条件、每一层要干的事

十个题都是这个套路,不再一一给出代码(一题递归一题for循环练习)

637.二叉树的层平均值

这个题是用for写感觉会好理解很多,递归写,要对遍历回来的数据进行遍历。自己写的时候苦恼的是无法获取层序号。借助了GPT,想到了字典的性质:用字典的key存序号,val是每层的值。

字典的新函数:dict.keys()--->获取所有key

注意key的索引是dict[key]

# 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 []

        levels = dict()#如果想用递归法写,如果用list存储无法查阅层数

        self.helper(root,0,levels)

        levels_avg = []
        for level in sorted(levels.keys()):#按keys的大小排序
            print(level)
            levels_avg.append(sum(levels[level])/len(levels[level]))
        return levels_avg

    def helper(self,node,level,levels):
        if not node:
            return

        if level not in levels:
            levels[level] = []  # 初始化每层的列表

        levels[level].append(node.val)#level是key
        self.helper(node.left,level+1,levels)
        self.helper(node.right,level+1,levels)

429.N叉树的层序遍历

同样的遍历模板,但是子节点不是用left、right来储存的,而是node.children这样储存的

"""
# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""
from collections import deque
class Solution:
    def levelOrder(self, root: 'Node') -> List[List[int]]:
        if not root:
            return []

        res = []
        deque = collections.deque([root])

        while deque:
            level = []
            for i in range(len(deque)):
                cur = deque.popleft()
                level.append(cur.val)

                # deque.append(cur.left) #一个节点有多个孩子因子不是用左右来储存
                # deque.append(cur.right)

                for child in cur.children:
                    deque.append(child)

            res.append(level)

        return res

如果要对每层中的数据做筛选还是for循环比较方便,递归简直是在为难自己……

226.翻转二叉树

不能用中序遍历做,中序遍历的顺序是左中右,在遍历左子树的时候就会对左子树操作一次,把他换到右子树,那么在做右子树的时候,会把这些节点再交换一遍,就又换回去了。

因此只能用前后序遍历做,或者层序遍历

哎呀,层序遍历比深度优先遍历好理解多了……比较符合我的思考逻辑……

可恶,怎么还优先掌握递归!!!!!

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
from collections import deque
class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root:
            return root

        deque = collections.deque([root])
        while deque:
            cur = deque.popleft()
            cur.left,cur.right = cur.right,cur.left#交换顺序

            if cur.left:
                deque.append(cur.left)
            if cur.right:
                deque.append(cur.right)
        
        return root

2、前序遍历的递归写法

# 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 
        
        self.dfs(root)
        return root

    #注意这个递归函数缩进和其他函数在同一个位置,而不是invertTree的子函数
    def dfs(self,node):#输入参数
        if not node:#终止条件
            return

        #每次递归要做的事
        node.left,node.right = node.right,node.left#交换节点

        self.dfs(node.left)#到下一个节点
        self.dfs(node.right)

前中后序思路差别不大,不再做复现

101.对称二叉树 2

这个题的思路完全6,左半边用前序遍历(中左右),右半边用后序遍历(左右中,非严格后序)

不可以按照这个顺序把左右子树全读出来之后在进行比较:只有一个子树时无法判断是哪个子树

outside:比较左半边的左子树和右半边的右子树

inside:比较左半边的右子树和右半边的左子树

# 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
        res = self.compara(root.left,root.right)
        return res


    def compara(self,leftnode,rightnode):#输入输出
        ## 要对比的结果(每层递归要做的事)+终止条件
        ##有空节点的三种情况
        if leftnode == None and rightnode != None: return False#
        elif leftnode != None and rightnode == None: return False
        elif leftnode == None and rightnode == None: return True
        # 无空节点,比较数值,注意是比较数值!!!
        elif leftnode.val != rightnode.val: return False

        #两个节点的值相等,跳到下一层比较
        outside = self.compara(leftnode.left,rightnode.right)#外侧那条路
        inside = self.compara(leftnode.right,rightnode.left)#内侧的一半

        return outside and inside#

补不过来了,二刷再来看其他方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值