题目描述
给定一个二叉树,每个节点上站一个人,节点数字表示父节点到该节点传递悄悄话需要花费的时间。
初始时,根节点所在位置的人有一个悄悄话想要传递给其他人,求二叉树所有节点上的人都接收到悄悄话花费的时间。
输入描述
给定二叉树
0 9 20 -1 -1 15 7 -1 -1 -1 -1 3 2
注:-1表示空节点
输出描述
返回所有节点都接收到悄悄话花费的时间
38
用例
输入 | 0 9 20 -1 -1 15 7 -1 -1 -1 -1 3 2 |
---|---|
输出 | 38 |
说明 | 无 |
解题思路
- 读取输入:
- 读取一行输入,这行输入包含了一系列的整数,每个整数代表从父节点到子节点的悄悄话传递时间。
- 处理根节点:
- 将根节点(索引为0)加入队列,并设置其悄悄话接收时间为0。
- 层次遍历:
- 当队列不为空时,循环执行以下步骤:
- 从队列中取出一个节点(包括节点索引和该节点的悄悄话接收时间)。
- 计算左右子节点的索引。
- 检查左右子节点是否存在(索引有效且不为-1)。
- 当队列不为空时,循环执行以下步骤:
- 更新子节点时间:
- 如果子节点存在,将当前节点的悄悄话接收时间加上从当前节点到子节点的悄悄话传递时间,得到子节点的悄悄话接收时间。
- 将子节点及其悄悄话接收时间加入队列。
- 更新最大时间:
- 每次子节点的悄悄话接收时间被计算后,更新最大时间为当前子节点时间和已记录的最大时间中的较大值。
模拟计算
给定的输入数组0 9 20 -1 -1 15 7 -1 -1 -1 -1 3 2
代表一棵二叉树,其中每个值代表从父节点到子节点的悄悄话传递时间。数组中的-1
表示没有子节点。数组索引代表节点的顺序,按照完全二叉树的顺序排列。
模拟计算过程如下:
-
初始化队列:
- 将根节点索引
0
加入队列,此时队列为[0]
。
- 将根节点索引
-
开始层次遍历:
- 队列非空,继续遍历。
-
处理根节点:
- 取出队列头部元素(根节点索引
0
),队列变为[]
。 - 计算左子节点索引
1
(2*0+1
),右子节点索引2
(2*0+2
)。 - 左子节点值为
9
,更新为0+9=9
,加入队列,队列变为[1]
。 - 右子节点值为
20
,更新为0+20=20
,加入队列,队列变为[1, 2]
。 - 更新
maxTime
为20
。
- 取出队列头部元素(根节点索引
-
处理索引为1的节点:
- 取出队列头部元素
1
,队列变为[2]
。 - 计算左子节点索引
3
(2*1+1
),右子节点索引4
(2*1+2
)。 - 左右子节点值均为
-1
,没有子节点,不做操作。
- 取出队列头部元素
-
处理索引为2的节点:
- 取出队列头部元素
2
,队列变为[]
。 - 计算左子节点索引
5
(2*2+1
),右子节点索引6
(2*2+2
)。 - 左子节点值为
15
,更新为20+15=35
,加入队列,队列变为[5]
。 - 右子节点值为
7
,更新为20+7=27
,加入队列,队列变为[5, 6]
。 - 更新
maxTime
为35
。
- 取出队列头部元素
-
处理索引为5的节点:
- 取出队列头部元素
5
,队列变为[6]
。 - 计算左子节点索引
11
(2*5+1
),右子节点索引12
(2*5+2
)。 - 左子节点值为
3
,更新为35+3=38
,加入队列,队列变为[6, 11]
。 - 右子节点值为
2
,更新为35+2=37
,加入队列,队列变为[6, 11, 12]
。 - 更新
maxTime
为38
。
- 取出队列头部元素
-
处理索引为6的节点:
- 取出队列头部元素
6
,队列变为[11, 12]
。 - 计算左子节点索引
13
(2*6+1
),右子节点索引14
(2*6+2
)。 - 由于索引超出数组长度,没有子节点,不做操作。
- 取出队列头部元素
-
处理索引为11和12的节点:
- 取出队列头部元素
11
和12
,队列变为[]
。 - 由于索引超出数组长度,没有子节点,不做操作。
- 取出队列头部元素
-
结束遍历:
- 队列为空,遍历结束。
-
输出结果:
- 最大时间
maxTime
为38
,这是最后一个节点接收悄悄话的时间。
- 最大时间
因此,所有节点接收悄悄话的总时间为38
。
根节点及对应值表示图
0(0)
/ \
9(1) 20(2)
/ \ / \
-1(3) -1(4) 15(5) 7(6)
/ \ / \ / \
-1(7)-1(8)-1(9)-1(10) 3(11) 2(12)
代码
from collections import deque
# 读取一行输入并将其转换为整数列表
# 列表中的每个元素代表从父节点到当前节点的时间
whisper_times = list(map(int, input().split()))
# 记录最后一个节点接收悄悄话的时间
max_time = 0
# 使用队列来进行二叉树的层次遍历
node_queue = deque([0]) # 将根节点索引0加入队列
# 当队列不为空时,继续遍历
while node_queue:
# 从队列中取出一个节点索引
parent_node_index = node_queue.popleft()
# 计算左子节点索引
left_child_index = 2 * parent_node_index + 1
# 计算右子节点索引
right_child_index = 2 * parent_node_index + 2
# 如果左子节点存在,处理左子节点
if left_child_index < len(whisper_times) and whisper_times[left_child_index] != -1:
# 更新左子节点的时间(父节点时间 + 当前节点时间)
whisper_times[left_child_index] += whisper_times[parent_node_index]
# 将左子节点加入队列
node_queue.append(left_child_index)
# 更新最大时间
max_time = max(max_time, whisper_times[left_child_index])
# 如果右子节点存在,处理右子节点
if right_child_index < len(whisper_times) and whisper_times[right_child_index] != -1:
# 更新右子节点的时间(父节点时间 + 当前节点时间)
whisper_times[right_child_index] += whisper_times[parent_node_index]
# 将右子节点加入队列
node_queue.append(right_child_index)
# 更新最大时间
max_time = max(max_time, whisper_times[right_child_index])
# 所有节点都接收到悄悄话后,打印最大时间
print(max_time)
双端队列数据结构deque
在使用 deque
之前,需要从 collections
模块中导入它:
from collections import deque
另:
node_queue = deque([0])
这里将一个包含单个元素 0
的列表 [0]
作为参数传递给 deque
构造函数,创建了一个初始内容为 [0]
的双端队列。
while node_queue:
# 从队列中取出一个节点索引
parent_node_index = node_queue.popleft()
1. while node_queue:
- 这是一个循环条件,表示只要
node_queue
非空,循环就会继续。 - 在 Python 中,空的
deque
(或其他容器类型)会被视为布尔值False
,而非空容器则被视为True
。
2. node_queue.popleft()
popleft()
是deque
的方法,用于从队列的左侧(头部)移除并返回一个元素。- 这种操作的时间复杂度为 O(1),非常高效。
- 返回的值被赋给变量
parent_node_index
,表示当前要处理的节点索引。