1、题目描述
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:
1 <---
/ \
2 3 <---
\ \
5 4 <---
2、代码详解
BFS(推荐解法)
对二叉树进行层次遍历,那么对于每层来说,最右边的结点一定是最后被遍历到的,记录下每层的最后一个元素。二叉树的层次遍历可以用广度优先搜索实现。
同:102. 二叉树的层序遍历
# 定义二叉树节点类
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):
# 如果根节点为空,直接返回空列表
if not root:
return []
# 初始化队列,用于层序遍历,队列中存储节点
queue = [] # 双端队列,存储TreeNode
queue.append(root)
# 用于存储右视图结果的列表
result = []
while len(queue) > 0:
# 当前层的节点数量
level_size = len(queue)
for i in range(level_size):
# 从队列中取出一个节点
queue_head = queue.pop(0)
# 如果是当前层的最后一个节点,将其值添加到结果列表中
if i == level_size - 1:
result.append(queue_head.val)
# 如果节点有左子节点,将左子节点加入队列
if queue_head.left:
queue.append(queue_head.left)
# 如果节点有右子节点,将右子节点加入队列
if queue_head.right:
queue.append(queue_head.right)
return result
def main():
# 构建一个简单的二叉树
# 1
# / \
# 2 3
# \ \
# 5 4
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.right = TreeNode(5)
root.right.right = TreeNode(4)
solution = Solution()
# 调用 rightSideView 方法获取二叉树的右视图
right_view = solution.rightSideView(root)
print("二叉树的右视图为:", right_view)
if __name__ == "__main__":
main()
优化:
- BFS 右孩子先进队的话,则每层的第一个节点即为该层最右的节点
- 这样不用统计每层节点数量,只通过层次变化来找每层第一个节点
deque 数据类型来自于collections 模块,支持从头和尾部的常数时间 append/pop 操作。若使用 Python 的 list,通过 list.pop(0) 去除头部会消耗 O(n)的时间。
- 时间复杂度 : O(n)。 每个节点最多进队列一次,出队列一次,因此广度优先搜索的复杂度为线性。
- 空间复杂度 : O(n)。每个节点最多进队列一次,所以队列长度最大不不超过 n,所以这里的空间代价为 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
BFS
- 用到 deque 的结构用来模拟队列,BFS精髓。
- 队列里肯定是有一个初始点
- 然后每次处理从队列中出队一个元素
- 对元素进行扩张(具体如何扩张需要根据题目要求)
- 对于扩张后满足某条件的点再进行处理,根据需要进入队列,进入队列的点就是扩到下一层的点(不同题目需要处理的方法不同,大家灵活运用)
- 然后接着循环处理 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