代码随想录算法训练营day15 | 层序遍历(广度优先搜索)

层序遍历(level order traversal):

  • trick:深度优先遍历用栈,层序优先遍历用队列

题目:

  • 102.二叉树的层序遍历(medium)

    • 迭代法

# 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

from collections import deque

class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        
        ans = []
        q = deque() #层序遍历(广度优先遍历)用队列
        
        if root is None:
            return ans
        else:
            q.append(root) #传入二叉树
   
        while q:
            size = len(q)
            temp = []
            for _ in range(size):
                node = q.popleft()
                temp.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            ans.append(temp) 
        return ans
  • 递归法

# 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]]:
        
        ans = []
        
        def helper(root, depth): #step1
            #step2: 终止条件(base condition)
            if root is None:
                return ans
            #step3: logic
            if len(ans) == depth:
                ans.append([]) #到达一层之后,要新增一个空list来存这一层的元素(指针)
            ans[depth].append(root.val)
            if root.left:
                helper(root.left, depth+1)
            if root.right:
                helper(root.right,depth+1)
        
        helper(root, 0) #从根节点层开始
        return ans
  • 107.二叉树的层次遍历II(medium)

    • 与102一样解法,迭代法 + 递归法, 只是返回ans[::-1]

  • 199.二叉树的右视图(medium)

    • 第一次写错误点如下:
    1. 以为只把右子树加入队列就好了
    2. 以为判断左子树不为空同时右子树为空,这样就能看到左子树的元素
    3. 经过上面两个错误,终于想到了只需要往结果集里加入每层最后一个元素就好。但是写的时候没想到可以直接q[-1]取到这个值
# 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

from collections import deque

class Solution(object):
    def rightSideView(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        ans = []
        q = deque()
        
        if root is None:
            return ans
        else:
            q.append(root)
            
        while q:
            size = len(q)
            for _ in range(size):
                node = q.popleft()
                ans.append(node.val)
                #if node.left and node.right is None:
                #    q.append(node.left)
                if node.right:
                    q.append(node.right)
            
        return ans
        
        
  •         迭代法:

# 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

from collections import deque

class Solution(object):
    def rightSideView(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        ans = []
        q = deque()
        
        if root is None:
            return ans
        else:
            q.append(root)
            
        while q:
            size = len(q)
            node = q[-1]
            ans.append(node.val)
            for i in range(size):
                node = q.popleft()
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            
        return ans
        
        
  •         递归法:

    • 依旧是取每一层的最后一个元素,那么就在最后增加一个遍历并添加到结果集
# 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]:
        
        ans = []
        temp = []
        def helper(root,depth): #step1
            #step2
            if root is None:
                return ans
            
            #step3
            if len(temp) == depth:
                temp.append([])
            temp[depth].append(root.val)
            if root.left:
                helper(root.left,depth+1)
            if root.right:
                helper(root.right,depth+1)
                
        helper(root,0)
        for i in range(len(temp)):
            ans.append(temp[i][-1])
        return ans
            
  • 637.二叉树的层平均值

    • 与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

from collections import deque

class Solution:
    def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
        
        ans = []
        q = deque()
        
        if root is None:
            return ans
        else:
            q.append(root)
            
        while q:
            size = len(q)
            temp = []
            for _ in range(size):
                node = q.popleft()
                temp.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
                
            ans.append(sum(temp) / len(temp))
                
        return ans
  •         递归法

    • 二刷时可以试试在helper内部是否可以实现求均值,目前这个写法只是非常直观。
# 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]:
        ans = []
        
        def helper(root, depth): #step1
            #step2
            if root is None:
                return ans
            #step3
            if len(ans) == depth:
                ans.append([])
            ans[depth].append(root.val)
            
            if root.left:
                helper(root.left, depth+1)
            if root.right:
                helper(root.right, depth+1)
            
        helper(root, 0)
        
        for i in range(len(ans)):
            ans[i] = sum(ans[i]) / len(ans[i])
        return ans
  • 429.N叉树的层序遍历(medium)

    • 注意N-ary树的定义

    • 错误点:首先完全按照模版来写, 通过打印type(root.children),知道children是一个list

    • 然后想取到这个list之后对其遍历然后加入temp数组,但结果报错说tree node不支持getitem

    • 参考题解发现只是改动了extend,因为children是一个list

extend用法;

# create a list
prime_numbers = [2, 3, 5]

# create another list
numbers = [1, 4]

# add all elements of prime_numbers to numbers
numbers.extend(prime_numbers)


print('List after extend():', numbers)

# Output: List after extend(): [1, 4, 2, 3, 5]
  •         题解:

    • 迭代法

"""
# 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]]:
        
        ans = []
        q = deque()
        
        if root is None:
            return ans
        else:
            q.append(root)
            
        while q:
            size = len(q)
            temp = []
            for _ in range(size):
                node = q.popleft()
                temp.append(node.val)
                if node.children:
                    q.extend(node.children)
                
            ans.append(temp)
            
        return ans
  •         递归法

"""
# 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]]:
        
        ans = []
        
        def helper(root, depth): #step1
            #step2
            if root is None:
                return ans
            #step3
            if len(ans) == depth:
                ans.append([])
            ans[depth].append(root.val)
            
            if root.children:
                for child in root.children:
                    helper(child, depth+1)
            
        helper(root, 0)
        return ans
  • 515.在每个树行中找最大值(medium)

    • 与102实际上是一样的,迭代法 + 递归法, 只需要将每个temp的最大值存到结果集即可。

  • 116.填充每个节点的下一个右侧节点指针(medium)

    • 迭代法

思路:

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

from collections import deque

class Solution:
    def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
        
        q = deque()
        
        if root is None:
            return None
        else:
            q.append(root)
            
        while q:
            cur = q.popleft()
            if cur.left: #perfect binary tree, if cur.left is not None, then cur.right is also not None.
                cur.left.next = cur.right
                if cur.next: 
                    cur.right.next = cur.next.left
                    
                q.append(cur.left)
                q.append(cur.right)
        
        return root
        
  • 递归法

"""
# 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
        """
        
        def helper(root): #step1
            #step2
            if root is None:
                return None
            
            #step3
            if root.left:
                root.left.next = root.right
                if root.next:
                    root.right.next = root.next.left
                    
                helper(root.left)
                helper(root.right)
        
        helper(root)
        return root
  • 117.填充每个节点的下一个右侧节点指针II(medium)

    • 看一下youtube视频

  • 104.二叉树的最大深度

    • 与102实际上是一样的,迭代法 + 递归法, 只是最后需要返回len(ans)

    • 除了上面的解法,也可以与111一样的解法:

# 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

from collections import deque
class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        
        q = deque()
        if root is None:
            return 0
        else:
            q.append(root)
        
        depth = 0
        while q:
            size = len(q)
            depth += 1
            for _ in range(size):
                node = q.popleft()
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
                    
        return depth
  • 111.二叉树的最小深度

    • trick: 只有当左子树和右子树同时为空时,说明遍历到了距离最短的最低点了

    • 因此,为了统一,104.二叉树的最大深度依然可以这样写,甚至不需要考虑左右子树都为空的情况

    • 题解:

# 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 minDepth(self, root: Optional[TreeNode]) -> int:
        
        q = deque()
        if root is None:
            return 0
        else:
            q.append(root)
        
        depth = 0
        while q:
            size = len(q)
            depth += 1
            for _ in range(size):
                node = q.popleft()
                
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
                
                if (not node.left) and (not node.right):
                    return depth
        # return depth
  • 226.翻转二叉树: 

    • trick:将左右叶子结点互换

    • 需要清楚用的是什么遍历方式

    • 迭代法-广度优先遍历:

# 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]:
        
        q = deque()
        if root is None:
            return None
        else:
            q.append(root)
            
        while q:
            size = len(q)
            for _ in range(size):
                node = q.popleft()
                node.left, node.right = node.right, node.left
                
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.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]:
        
        stack = []
        if root is None:
            return root
        else:
            stack.append(root)
            
        while stack:
            node = stack.pop()
            node.left, node.right = node.right, node.left
            
            if node.right:
                stack.append(node.right)
            if node.left:
                stack.append(node.left)
            
        return root
  • 递归法(前序遍历):

# 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):
    #因为要求返回root,那么就可以直接用题目定义好的函数
    def invertTree(self, root): #step1
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        #step2
        if root is None:
            return root
        #step3
        root.left, root.right = root.right, root.left
        self.invertTree(root.left)
        self.invertTree(root.right)
        
        return root
        
  • 101. 对称二叉树

    • 思路:对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的。因此要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树(也是函数需要的参数)。

    • 经过分析,本题遍历只能是“后序遍历”,因为要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。只有在比较了左和右之后,并把信息返回给中,这样才能判断左右子树是否可以相互翻转。因此顺序是 左右中-->后序遍历。

    • 递归法:(参考代码随想录)

      • 递归三部曲以及对应分析
  • 100.相同的树

  • 572.另一个树的子树

总结:

  1. 要深刻理解解题思路,很多题只是不同的问法而已,实际上都是一样的,只是最后需要添加到结果集的元素不一样。

  2. 针对二叉树的问题,解题之前一定要想清楚用哪种遍历方式,究竟是前中后序遍历,还是层序遍历。

  3. 深度优先遍历借助栈, 广度优先遍历借助队列。

  4. 回看深度优先遍历的写法,除了借助栈之外,其实逻辑和写法是一样的。

  5. 对于对称二叉树还需继续研究,以及相似的两道题。详细的分析看代码随想录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值