华为OD机试真题中的“传递悄悄话”题目,主要考察的是对二叉树遍历和路径时间累加的理解。在这个问题中,家庭成员站在由二叉树形式组织的位置上,每个人之间的连接代表一条传递悄悄话的路径,且每条路径上有一个时间消耗。根位置的K小姐想将一个悄悄话传递给所有人,需要计算使得所有家庭成员都听到这个悄悄话所需的最长时间。
一、题目描述
- 输入:包含一行,由空格隔开的整数序列。这个序列以层序遍历的方式描述了一个二叉树,其中-1表示空节点。序列的第一个数字是根节点,表示从K小姐开始的时间为0。
- 输出:一个整数,表示所有节点都接收到悄悄话的最长时间。
二、解题思路
-
解析输入:首先,将输入的整数序列解析为一个二叉树的结构。由于输入是层序遍历的序列,我们可以直接利用这个序列来模拟二叉树的遍历过程,而无需显式地构建二叉树。
-
遍历二叉树:使用队列(Queue)来进行层序遍历。队列中存储的是当前需要遍历的节点索引和到达该节点所需的时间。初始时,将根节点(索引为0,时间为0)加入队列。
-
计算时间:在遍历过程中,对于队列中的每个节点,计算其左右子节点(如果存在)的到达时间,并将这些子节点及其到达时间加入队列。到达时间是通过将父节点的到达时间加上从父节点到子节点的额外时间得到的。
-
记录最大时间:在遍历过程中,记录并更新从根节点到所有节点的最大到达时间。这个最大时间即为所有节点都接收到悄悄话所需的最长时间。
-
输出结果:遍历结束后,输出记录的最大时间。
示例
假设输入为0 9 20 -1 -1 15 7 -1 -1 -1 -1 3 2
,则对应的二叉树结构如下(其中-1表示空节点):
0
/ \
9 20
/ \
15 7
/
3
/
2
按照上述思路进行遍历和计算,最终得到的最长时间为38(从根节点到最远的叶子节点的路径时间)。
三、注意事项
- 输入的二叉树节点个数可能很大,需要确保算法的时间复杂度和空间复杂度都是可接受的。
- 输入中的时间都是非负整数,且不超过某个给定的上限。
- 在实际编程时,需要注意处理边界情况,如空树(输入序列只有一个-1)或只有一个节点的树等。
四、代码示例(简单版)
import java.util.LinkedList;
import java.util.Queue;
public class WhisperPassing {
public static void main(String[] args) {
// 这里为了示例,我们直接使用一个静态数组作为输入
// 在实际应用中,你可能需要从文件、控制台或其他输入源读取这个数组
int[] treeSequence = {0, 9, 20, -1, -1, 15, 7, -1, -1, -1, -1, 3, 2};
// 调用函数并输出结果
System.out.println(maxTimeToReachAllNodes(treeSequence));
}
/**
* 计算到达树中所有节点的最大时间
*
* @param treeSequence 树的节点序列,表示每个节点到其父节点的时间,根节点时间视为0
* @return 所有节点中到达的最大时间
*/
public static int maxTimeToReachAllNodes(int[] treeSequence) {
// 如果输入数组为空或长度为0,则直接返回0,因为没有节点需要到达
if (treeSequence == null || treeSequence.length == 0) {
return 0; // 或者抛出异常,取决于你的需求
}
// 使用队列来存储节点索引和到达该节点的时间
Queue<int[]> queue = new LinkedList<>();
// 将根节点(索引0)和到达时间(0)加入队列
queue.offer(new int[]{0, 0});
// 初始化最大时间为0
int maxTime = 0;
// 由于我们处理的是层序遍历的数组,可以通过简单的计算获取子节点索引,无需额外函数
int index = 0; // 当前处理的节点索引
// 遍历队列中的每个节点
while (!queue.isEmpty()) {
int[] current = queue.poll();
index = current[0];
int currentTime = current[1];
// 更新最大时间
maxTime = Math.max(maxTime, currentTime);
// 计算左右子节点的索引
int leftIndex = 2 * index + 1;
int rightIndex = 2 * index + 2;
// 检查并添加左子节点到队列
if (leftIndex < treeSequence.length && treeSequence[leftIndex] != -1) {
queue.offer(new int[]{leftIndex, currentTime + treeSequence[leftIndex]});
}
// 检查并添加右子节点到队列
if (rightIndex < treeSequence.length && treeSequence[rightIndex] != -1) {
queue.offer(new int[]{rightIndex, currentTime + treeSequence[rightIndex]});
}
}
// 返回计算出的最大时间
return maxTime;
}
// 注意:上面的实现假设了输入数组是有效的层序遍历序列,并且没有额外的检查来验证这一点。
// 在实际应用中,你可能需要添加额外的逻辑来验证输入的有效性。
}
代码示例(详细版)
考虑添加一些额外的功能,比如从标准输入读取数据、验证输入的有效性、以及更详细地处理二叉树的层序遍历
下面是一个更复杂的Java实现,它包含了从标准输入读取层序遍历序列的功能,并对输入进行了一些基本的验证:
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class WhisperPassingComplex {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 提示用户输入层序遍历的序列,以空格分隔,输入-1结束序列
System.out.println("请输入层序遍历的序列(以空格分隔,-1表示空节点):");
String input = scanner.nextLine();
// 解析输入字符串为整数数组
String[] tokens = input.trim().split("\\s+");
int[] treeSequence = new int[tokens.length];
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].equals("-1")) {
treeSequence[i] = -1;
} else {
try {
treeSequence[i] = Integer.parseInt(tokens[i]);
} catch (NumberFormatException e) {
System.err.println("输入包含无效数字,请重新输入。");
return;
}
}
}
// 调用函数并输出结果
int maxTime = maxTimeToReachAllNodes(treeSequence);
System.out.println("所有节点都接收到悄悄话所需的最长时间为:" + maxTime);
}
public static int maxTimeToReachAllNodes(int[] treeSequence) {
if (treeSequence == null || treeSequence.length == 0 || treeSequence[0] < 0) {
throw new IllegalArgumentException("无效的输入序列");
}
Queue<int[]> queue = new LinkedList<>(); // 存储节点索引和到达时间的队列
queue.offer(new int[]{0, 0}); // 根节点索引为0,到达时间为0
int maxTime = 0;
int index = 0; // 当前处理的节点索引
while (!queue.isEmpty()) {
int[] current = queue.poll();
index = current[0];
int currentTime = current[1];
maxTime = Math.max(maxTime, currentTime); // 更新最大时间
// 计算左右子节点的索引(注意边界和-1的处理)
int leftIndex = 2 * index + 1;
int rightIndex = 2 * index + 2;
// 检查左子节点是否存在且不是-1
if (leftIndex < treeSequence.length && treeSequence[leftIndex] != -1) {
queue.offer(new int[]{leftIndex, currentTime + treeSequence[leftIndex]});
}
// 检查右子节点是否存在且不是-1
if (rightIndex < treeSequence.length && treeSequence[rightIndex] != -1) {
queue.offer(new int[]{rightIndex, currentTime + treeSequence[rightIndex]});
}
}
return maxTime;
}
}
在这个实现中,我们:
- 使用
Scanner
类从标准输入读取一行文本。 - 将输入的字符串按空格分割成多个标记,并将它们转换为整数数组(对-1进行特殊处理)。
- 在将数组传递给
maxTimeToReachAllNodes
函数之前,对输入进行了一些基本的验证。 - 在
maxTimeToReachAllNodes
函数中,我们使用队列来模拟层序遍历过程,并计算从根节点到所有节点的最大到达时间。 - 最后,我们输出了所有节点都接收到悄悄话所需的最长时间。