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

层序遍历(102)

理论基础

BFS 在树中的体现。与 DFS 不同的是,优先广度的搜索需要层级顺序,从而需要队列来进行实现。
思路:将每一层的节点都保存在队列中,通过额外的变量 size 来记录当前层中的节点数量(在每次对同一层的节点开始遍历前记录)。

题目链接

迭代

class Solution:
    from collections import deque
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        if root == None:
            return []
        
        results = []
        queue = deque()
        queue.append(root)
        while (len(queue) > 0):
            size = len(queue)
            temp_lst = []
            # it can be len(queue), although queue is dynamic in this while loop
            # when the loop is called first time, len(queue) is fixed
            # but this format will be confusing
            for i in range(size):       
                curr_node = queue.popleft()
                temp_lst.append(curr_node.val)
                if curr_node.left != None:
                    queue.append(curr_node.left)
                if curr_node.right != None:
                    queue.append(curr_node.right)
            results.append(temp_lst)
        return results

递归

递归的思路完成层次遍历还是像其他的递归一样轻松,但注意这里多了一个不容易想到的变量 level,主要是记录当前到达的层数。这不属于递归终止条件,而是题目中的结构要求,即用 level 标记是否是第一次到达该层,如果是则添加新的 [] 来储存该层的节点值。
主要是递归思路的锻炼。

class Solution:
    def levelRec(self, root: Optional[TreeNode], results: List[List[int]], level: int) -> None:
        if root == None:
            return results
        
        if len(results) == level:       # first time reach this new level
            results.append([])
        results[level].append(root.val)
        self.levelRec(root.left, results, level + 1)
        self.levelRec(root.right, results, level + 1)


    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        results = []
        self.levelRec(root, results, 0)
        return results

226. 翻转二叉树

题目链接 | 解题思路

递归的思路是较为简单的,在单层遍历中,交换当前节点的左右子节点即可。对于左右节点的递归必须连在一起进行,所以前序和后序遍历都是可以的。而中序遍历会很 tricky,因为只翻转一个子节点之后进行节点的更新,可能会再次翻转相同的节点(中序可以解,但思路上会很麻烦)。

重要的是,要意识到自己要使用什么顺序的遍历。这里面涉及两点:

  1. 自己当前的思路是什么样的遍历顺序?
  2. 为什么要使用这样的遍历顺序?

不同的遍历顺序代表了对获取信息的顺序要求,所以实际上是根据题目中的信息顺序来决定遍历顺序。

前序遍历

class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if root == None:
            return 
        temp_left = self.invertTree(root.left)
        temp_right = self.invertTree(root.right)
        root.left, root.right = temp_right, temp_left
        return root

层次遍历

BFS 的层次遍历同样可以解决,对每层的每个节点进行左右子节点的翻转即可。

class Solution:
    def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if root == None:
            return None
        
        stack = [root]
        while (len(stack) > 0):
            size = len(stack)
            for i in range(size):
                curr_node = stack.pop()
                curr_node.left, curr_node.right = curr_node.right, curr_node.left
                if curr_node.left != None:
                    stack.append(curr_node.left)
                if curr_node.right != None:
                    stack.append(curr_node.right)
        return root

101. 对称二叉树

题目链接 | 解题思路

读懂题目的目标非常重要。这题和上一题最大的不同在于,递归中的单层逻辑不能仅依靠当前节点的子节点(例如,比较子节点是否相等),还需要子节点的子节点。

这里要比较的是外侧与外侧节点,内侧与内侧节点,所以对于左右子树来说,遍历(比较)顺序应该是相反的,即一个子树是“左右中”,一个子树是“右左中”。

此题的重点思路是,只有完成了子节点(的子节点)的比较,才能得知当前节点的信息,从而决定是向上传递还是可以直接返回。这是一种广义上的后序遍历,即“当前节点的信息依赖于子节点的信息”。分析出广义后序是这道题的递归方向最大的重点!

另外一点是要清晰地分析当前递归的终止条件(此题比较复杂),递归的参数(同时从左右子树出发,所以需要左节点和右节点,而非单一的当前节点)。

后序遍历

class Solution:
    def compare(self, left_node: Optional[TreeNode], right_node: Optional[TreeNode]) -> bool:
        if left_node == None and right_node == None:
            return True
        elif left_node != None and right_node == None:
            return False
        elif left_node == None and right_node != None:
            return False
        elif left_node.val != right_node.val:
            return False
        else:
            outside = self.compare(left_node.left, right_node.right)	# left, right
            inside = self.compare(left_node.right, right_node.left)		# right, left
            return outside and inside									# middle

    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        if root == None:
            return True
        return self.compare(root.left, root.right)

层次遍历

较为直接的方法,直接遍历每一层并检查当前层是否回文。

class Solution:
    from collections import deque
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        if root == None:
            return True
        
        queue = deque([root])
        while (len(queue) > 0):
            size = len(queue)
            curr_lst = []
            for i in range(size):
                curr_node = queue.popleft()
                if curr_node != None:
                    curr_lst.append(curr_node.val)
                    queue.append(curr_node.left)
                    queue.append(curr_node.right)
                else:
                    curr_lst.append(None)
            if curr_lst != curr_lst[::-1]:
                return False
        return True
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值