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

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

层序遍历

102. 二叉树的层序遍历

题目链接: 102.二叉树的层序遍历

需要用到队列,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑

这种层序遍历方式就是图论中的广度优先遍历

层次遍历动画如下:

请添加图片描述

代码:

自己做

因为题目中是按层返回结点信息的,如果采用队列的方式,不知道如何按层返回结点信息,所以我就采用了递归的方式,每次返回都是一层的结点信息。

python

# 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 levelOrderTraverse(self, lst, result):
        if len(lst) == 0:
            return None
        else:
            sub_list = []
            nextLevel_list = []
            for node in lst:
                sub_list.append(node.val)
                if node.left: nextLevel_list.append(node.left)
                if node.right: nextLevel_list.append(node.right)
            result.append(sub_list)
            return self.levelOrderTraverse(nextLevel_list, result)

        
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        # 思想:
        '''
        1. 创建一个队列
        2. 只要队列不等于空,那么出队,然后将其左孩子和右孩子送入队列中,知道队列为空
        注意:如何记录哪些结点属于哪一层呢?
        好像递归更好记录层次信息,每次return 层次加1
        '''
        result = []
        lst = []

        if root: 
            lst.append(root)
        else:
            return []
        
        self.levelOrderTraverse(lst, result)

        return result

代码随想录

采用队列的方式:

for _ in range(len(queue)): # 点睛之笔!!!只遍历每层结点的长度

python

from collections import deque
# 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]) # 这里root要加[],因为deque类接受数据类型必须为可迭代数据类型

        result = []

        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)
            result.append(level)
        return result

递归的方式:

这个递归方式没有自己写的好理解

# 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 
        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)

接下来为10道用到层次遍历的题

107.二叉树的层次遍历 II

107.二叉树的层次遍历 II

反转result列表即可

result[::-1]

199.二叉树的右视图

199.二叉树的右视图

在这里插入图片描述

方法一:

	return [result[-1] for result in result]

方法二:

	 result.append(level[-1]) # level为每层的结点列表
 return result

637.二叉树的层平均值

637.二叉树的层平均值

改进方法一:(时间复杂度会很高!)

result.append(float(sum(level))/len(level))
    return result

改进方法二:

level_sum = 0.0
level_len = 0
for _ in range(len(queue)): # 点睛之笔!!!只遍历每层结点的长度
    cur = queue.popleft()
    level_sum += cur.val
    level_len += 1
    if cur.left:
        queue.append(cur.left)
    if cur.right:
        queue.append(cur.right)
result.append(level_sum/level_len)

429. N 叉树的层序遍历

429. N 叉树的层序遍历

思想:

框架与二叉树的层次遍历一致

注意

collections.deque是一个类,如果直接传参进行初始化,需要传入可迭代的对象

方式一:

queue = collections.deque([root])

方式二:

queue = collections.deque()
queue.append(root)

n叉树的children为可迭代对象,需要使用for循环进行遍历

代码:

python

from collections import deque
"""
# 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 []
        
        queue = deque()
        queue.append(root)

        result = []

        while queue:
            level = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                level.append(cur.val)
                for child in cur.children:
                    queue.append(child)
            result.append(level)
        return result

515.在每个树行中找最大值

515.在每个树行中找最大值

代码改写部分:

python

cur_level_max = -2e31
for _ in range(len(queue)): # 点睛之笔!!!只遍历每层结点的长度
    cur = queue.popleft()
    if cur.val > cur_level_max: cur_level_max = cur.val
    if cur.left:
        queue.append(cur.left)
    if cur.right:
        queue.append(cur.right)
result.append(cur_level_max)

116. 填充每个节点的下一个右侧节点指针

116. 填充每个节点的下一个右侧节点指针

思想:

这道题可能是脑子不好用了,没有做出来…

本题依然是层序遍历,只不过在单层遍历的时候记录一下 本层的头部节点 ,然后在遍历的时候让前一个节点指向本节点就可以了

代码:

python

from collections import deque
"""
# 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 = deque()
        queue.append(root)

        while queue:
            level_size = len(queue)
            prev = None
            
            for i in range(level_size):
                node = queue.popleft()
                
                # 重要的步骤
                if prev:
                    prev.next = node
                
                prev = node
                
                if node.left:
                    queue.append(node.left)
                
                if node.right:
                    queue.append(node.right)
                
        return root 

117.填充每个节点的下一个右侧节点指针II

117.填充每个节点的下一个右侧节点指针II

同上一题

这道题目说是二叉树,但116题目说是完整二叉树,其实没有任何差别,一样的代码一样的逻辑一样的味道

104.二叉树的最大深度

104.二叉树的最大深度

思想:

有几层的问题

使用迭代法的话,使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。

111.二叉树的最小深度

111.二叉树的最小深度

思想:

需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点

我当时想的是如果当前层的结点数量小于2**(level-1) 的话就说明到了最小深度,这种想法是不对的。反例:一条斜线的二叉树

代码:

python

# 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
        depth = 0
        queue = collections.deque([root])
        
        while queue:
            depth += 1 
            for _ in range(len(queue)):
                node = queue.popleft()
                
                if not node.left and not node.right:
                    return depth
            
                if node.left:
                    queue.append(node.left)
                    
                if node.right:
                    queue.append(node.right)

        return depth

致敬叶师傅!(连着打了10个小怪,真累坏了)

噗,终于结束了…

226.翻转二叉树

226.翻转二叉树

自己做

思想:

从上到下遍历和从下到上遍历应该是一样的

使用递归:

  1. 传入参数:root
  2. 单层操作:交换左右结点
  3. 返回条件:无左右孩子结点

代码:

python

# 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 root :
            cur = root
            self.helper(cur)

        return root
    
    def helper(self, cur):
        if cur.left != None or cur.right != None:
            temp = cur.left
            cur.left = cur.right
            cur.right = temp
        if cur.left != None:
            self.helper(cur.left)
        if cur.right != None:
            self.helper(cur.right)
        if cur.left == None and cur.right == None:
            return 

代码随想录

思想:

只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果

这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了

那么**层序遍历可以不可以呢?依然可以的!**只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!

注意

二叉树解题的大忌就是自己稀里糊涂的过了(因为这道题相对简单),但是也不知道自己是怎么遍历的。

针对翻转二叉树,我给出了一种递归,三种迭代(两种模拟深度优先遍历,一种层序遍历)的写法,都是之前我们讲过的写法,融汇贯通一下而已。

大家一定也有自己的解法,但一定要成方法论,这样才能通用,才能举一反三!

代码:

递归法

# 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: TreeNode) -> TreeNode:
        if not root:
            return None
        root.left, root.right = root.right, root.left
        self.invertTree(root.left)
        self.invertTree(root.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: TreeNode) -> TreeNode:
        if not root:
            return None      
        stack = [root]        
        while stack:
            node = stack.pop()   
            node.left, node.right = node.right, node.left                   
            if node.left:
                stack.append(node.left)
            if node.right:
                stack.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: TreeNode) -> TreeNode:
        if not root:
            return None
        self.invertTree(root.left)
        root.left, root.right = root.right, root.left
        self.invertTree(root.left)
        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: TreeNode) -> TreeNode:
        if not root:
            return None      
        stack = [root]        
        while stack:
            node = stack.pop()                   
            if node.left:
                stack.append(node.left)
            node.left, node.right = node.right, node.left               
            if node.left:
                stack.append(node.left)       
        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: TreeNode) -> TreeNode:
        if not root:
            return None
        self.invertTree(root.left)
        self.invertTree(root.right)
        root.left, root.right = root.right, root.left
        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: TreeNode) -> TreeNode:
        if not root:
            return None      
        stack = [root]        
        while stack:
            node = stack.pop()                   
            if node.left:
                stack.append(node.left)
            if node.right:
                stack.append(node.right)  
            node.left, node.right = node.right, node.left               
     
        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: TreeNode) -> TreeNode:
        if not root: 
            return None

        queue = collections.deque([root])    
        while queue:
            for i 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. 对称二叉树

101. 对称二叉树

自己做

思想:

代码:

代码随想录

思想:

本题遍历只能是“后序遍历”,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。

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

代码:

python

递归法

递归三部曲:

  1. 确定递归函数的参数和返回值

  2. 确定终止条件

  3. 确定单层递归的逻辑

# 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 False
        
        return self.compare(root.left, root.right)

    def compare(self, left, right): # 1. 确定递归函数的参数和返回值
    	# 2. 确定终止条件
        if not left and not right: # 
            return True
        elif not left and right:
            return False
        elif left and not right:
            return False
        elif left.val != right.val:
            return False
        
        # 3. 确定单层递归的逻辑
        outside = self.compare(left.left, right.right)
        inside = self.compare(left.right, right.left)
        return outside and inside

迭代法

  1. 使用队列

请添加图片描述

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
  1. 使用栈

把左右两个子树要比较的元素顺序放进一个容器,然后成对成对的取出来进行比较,

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if not root:
            return True
        st = [] #这里改成了栈
        st.append(root.left)
        st.append(root.right)
        while st:
            rightNode = st.pop()
            leftNode = st.pop()
            if not leftNode and not rightNode:
                continue
            if not leftNode or not rightNode or leftNode.val != rightNode.val:
                return False
            st.append(leftNode.left)
            st.append(rightNode.right)
            st.append(leftNode.right)
            st.append(rightNode.left)
        return True
  1. 层次遍历
class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if not root:
            return True
        
        queue = collections.deque([root.left, root.right])
        
        while queue:
            level_size = len(queue)
            
            if level_size % 2 != 0:
                return False
            
            level_vals = []
            for i in range(level_size):
                node = queue.popleft()
                if node:
                    level_vals.append(node.val)
                    queue.append(node.left)
                    queue.append(node.right)
                else:
                    level_vals.append(None)
                    
            if level_vals != level_vals[::-1]:
                return False
            
        return True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值