代码随想录算法训练营第十八天 | 二叉树的层序遍历 226.翻转二叉树 101. 对称二叉树

二叉树的层序遍历

文档讲解:代码随想录

题目链接:. - 力扣(LeetCode)

二叉树每一层的数值放在一个数组里,最后返回的就是一个二维数组

在二叉树本身的结构中,我们是无法做到层序遍历的,如下图,第一层我们可以遍历完,但是当遍历到第二层,9和20之间是没有联系的,遍历完9是无法遍历到20的。或者说我们遍历20时,要把9保存起来,并且知道它们在同一层。

我们借助一个队列来遍历二叉树,先遍历到的元素就是我们最后数组中的节点顺序,会先保存起来。我们要记录每一层的大小,并且要知道下一层的元素有哪些,就需要在队列中弹出元素的同时加入该元素的左右节点,因为此时队列中不仅有当前层的元素还有下一层的元素,所以我们会利用之前记录的每一层的大小,弹出相应的节点,即为当前层的元素

class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        result = [] #最终的结果数组
        if not root:
            return []
        #定义一个队列
        queue = collections.deque([root])
        while queue:
            mid = []#记录每一层的数值
            size = len(queue) #记录每一层大小
            for _ in range(size):
                node = queue.popleft() #右入左出
                mid.append(node.val)
                if node.left:
                    queue.append(node.left) #加入相应节点的左节点,这里可能是空加入到队列之后,下面弹出的时候node是none会报错
                if node.right:                    
                    queue.append(node.right) #加入相应节点的右节点
            result.append(mid)
        return result

注:

deque 数据类型来自于collections 模块,支持从头和尾部的常数时间 append/pop 操作。若使用 Python 的 list,通过 list.pop(0) 去除头部会消耗 O(n)的时间。

226.翻转二叉树

文档讲解:代码随想录

题目链接:. - 力扣(LeetCode)

 只要交换每一个节点对应的左右节点即可。按什么顺序来处理每一个节点呢,可以采用深度优先(前中后序)或者广度优先

深度优先遍历(递归)

前序遍历

中左右

class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        def reverse(root):
            if not root:  # 如果根节点为空
                return []  # 返回空列表,结束递归
            root.left, root.right = root.right, root.left  # 交换左右子树
            reverse(root.left)  # 递归处理左子树
            reverse(root.right)  # 递归处理右子树
        reverse(root)  # 调用递归函数
        return root  # 返回反转后的根节点

中序遍历

左中右

如果按照前序遍历的改,那么本来一开始处理的就是左子树, 再处理中交换左右结点之后,左子树变成了现在的右子树,接下来处理右子树,遍历的就是原来的左子树,那么右子树就是没有处理

所以最后应该处理的还是左子树,也就是交换之前的右子树

###中序遍历
class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        def reverse(root):
            if not root: #1
                return []#2
            reverse(root.left)#3
            root.left,root.right = root.right,root.left#4
            reverse(root.left)#5
        reverse(root)
        return root

后序遍历

###后序遍历
class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        def reverse(root):
            if not root: #1
                return []#2
            reverse(root.left)#3
            reverse(root.right)#4
            root.left,root.right = root.right,root.left#5
        reverse(root)
        return root 

广度优先遍历(层序)

class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root:
            return  None
        deque = collections.deque([root])
        while deque:
            ###翻转每一层
            for _ in range(len(deque)):
                node = deque.popleft() #该层的节点
                node.left,node.right = node.right,node.left #翻转每一个遍历到的节点
                if node.left:
                    deque.append(node.left)
                if node.right:
                    deque.append(node.right)
        return root

101. 对称二叉树

文档讲解:代码随想录

题目链接:. - 力扣(LeetCode)

没有怎么懂┭┮﹏┭┮

要点: 从根节点出发的两个节点(node1,node2)。node1如果向左,那么node2向右的值就得与其相等;如果node1向右,那么node2向左的值就与其相等。即我们要同时判断node1->left == node2->right和node1->right == node2->left。如果两者皆满足,那这就是一个对称的二叉树。

二叉树最终是考察我们如何遍历的, 那么我们应该使用前中后序哪一个遍历方式呢.只能使用后序(左右中)。 只有后序遍历,才能把底部孩子的信息 返回给上一层

对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。我们的递归函数的传入参数就是左右子树

明确递归什么时候结束:

①左右都为空,肯定是对称的:返回true

②有一个为空一个不为空,肯定不是对称的了:返回false ③都不为空且值相等,那么要继续递归判断

class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        if not root:
            return False
        return self.compare(root.left,root.right)

    def compare(self,left,right):
        if left ==None and right != None:
            return False
        if left !=None and right == None:
            return False
        if left ==None and right==None:
            return True
        if left.val != right.val:
            return False
        #在比较外面的过程中,如果遇到了不对称的情况就直接返回了false
        outside = self.compare(left.left,right.right) 
        ##在比较里面的过程中,如果遇到了不对称的情况就直接返回了false
        inside = self.compare(left.right,right.left)

        return outside and inside

补充:感觉递归的主要作用是判断当前两个节点值是否满足对称的要求,我们主要的要写的就是如何遍历值,也就是如何传给递归函数实参,outside和inside,只要在遍历过程中有一个是false了,那么这个false就会影响到最后的结果是false

更新

后续新理解:递归的作用就是判断两颗二叉树是否可以翻转,就要比较是否node1->left == node2->right和node1->right == node2->left,如果不等,就可以判断出不可以翻转了,如果相等,那么接下来还要继续判断,此时就可以将2个二叉树分解为4个二叉树了,两两比较,分别是外外和内内,内外都可以翻转才是翻转二叉树

  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值