LeetCode199. 二叉树的右视图(BFS)

1、题目描述

https://leetcode-cn.com/problems/binary-tree-right-side-view/

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---

2、代码详解

BFS(推荐解法)

对二叉树进行层次遍历,那么对于每层来说,最右边的结点一定是最后被遍历到的,记录下每层的最后一个元素。二叉树的层次遍历可以用广度优先搜索实现。

优化:

  • BFS 右孩子先进队的话,则每层的第一个节点即为该层最右的节点  
  • 这样不用统计每层节点数量,只通过层次变化来找每层第一个节点

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

  • 时间复杂度 : O(n)。 每个节点最多进队列一次,出队列一次,因此广度优先搜索的复杂度为线性。  
  • 空间复杂度 : O(n)。每个节点最多进队列一次,所以队列长度最大不不超过 nn,所以这里的空间代价为 O(n)。
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def rightSideView(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        import collections
        if not root:
            return []
        res = []
        queue = collections.deque([(root, 1)])  # (node, depth)
        layer = 0
        while queue:
            top = queue.popleft()
            if top[1] != layer:  # this layer's first node
                res.append(top[0].val)
                layer += 1  # go next layer
            if top[0].right:  # right child first in
                queue.append((top[0].right, top[1] + 1))
            if top[0].left:
                queue.append((top[0].left, top[1] + 1))
        return res

https://leetcode-cn.com/problems/binary-tree-right-side-view/solution/jian-dan-bfsdfs-bi-xu-miao-dong-by-sweetiee/

BFS

  1. 用到 deque 的结构用来模拟队列,BFS精髓。
  2. 队列里肯定是有一个初始点
  3. 然后每次处理从队列中出队一个元素
  4. 对元素进行扩张(具体如何扩张需要根据题目要求)
  5. 对于扩张后满足某条件的点再进行处理,根据需要进入队列,进入队列的点就是扩到下一层的点(不同题目需要处理的方法不同,大家灵活运用)
  6. 然后接着循环处理 deque 中的元素,直到 deque 为空,则代表所有点都已经完成扩张
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def rightSideView(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        res = []
        tmp_layer = collections.deque()  # 还是BFS用到的queue
        tmp_layer.append(root)  # 先将初始节点压入
        while len(tmp_layer) > 0:
            count = 0  # 计数,用来记录是某一层的第几个元素
            next_layer = []
            while len(tmp_layer) > 0:  # 处理某一层的节点
                tmp_node = tmp_layer.popleft()
                if count == 0:  # 只要最右侧的元素,所以根据下面先压入队列的是右子树,后压入左子树,我们只要队列中的第一个元素
                    res.append(tmp_node.val)
                count += 1
                # 将某个节点的右左子树压入
                if tmp_node.right is not None:
                    next_layer.append(tmp_node.right)
                if tmp_node.left is not None:
                    next_layer.append(tmp_node.left)
            tmp_layer = collections.deque(next_layer)  # 更新下一层的tmp
        return res

DFS

核心思路:优先找右侧子树。如果右侧走完了,就回退。本质上把树遍历了一遍。然后把优先出现的当前层的【最右侧节点的数值】存入结果列表中。

打印的是 值&层数。把每层第一次出现的值存入列表中即可。因为不存在断层的情况,可以直接用 append() 追加到最后。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def __init__(self):
        self.res = [] #初始化结果列表

    #增加一个参数 level 表示层数,初始值设置为1,表示第一层
    def rightSideView(self, root, level=1):
        if root == None:
            return []
        # print(root.val,level) #调试用

        # 如果层数超过现有的元素量,代表要记录节点到对应的位置了。
        # 之后就不用了。一层只需要第一次出现的最右边的那个
        if level > len(self.res):
            self.res.append(root.val) #直接append()到最后即可。因为不存在跳层数的情况。

        #优先走右侧子树。不行再回退走左侧子树。
        #基于当前层数加一。注意这里使用的是参数形式的level。并非全局的。
        self.rightSideView(root.right,level+1) 
        #基于当前层数加一。注意这里使用的是参数形式的level。并非全局的。
        self.rightSideView(root.left,level+1) 

        return self.res

https://leetcode-cn.com/problems/binary-tree-right-side-view/solution/python3-di-gui-jie-fa-by-mu-ren-6/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值