华为OD机试 2024E卷题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。
一、题目描述
通常使用多行的节点,父节点Q表示一棵树,比如:
西安 陕西
陕西 中国
江西 中国
中国 亚洲
泰国 亚洲
输入一个节点之后,请打印出来树中他的所有下层节点。
二、输入描述
第一行输入行数,下面是多行数据,每行以空格区分节点和父节点,接着是查询节点。
三、输出描述
输出查询节点的所有下层节点,以字典序排序。
备注
树中的节点是唯一的,不会出现在两节点中,是同一个名字。
ACM输入输出模式
如果你经常使用Leetcode, 会知道Leetcode是不需要编写输入输出函数的。但是华为OD机考使用的是ACM模式,需要手动编写输入和输出。
所以最好在华为-客上提前熟悉这种模式。例如C++使用cin/cout,python使用input()/print()。JavaScript使用node的readline()和console.log()。Java使用scanner/system.out.print()。
四、测试用例
测试用例1:
1、输入
5
b a
c a
d c
e c
f d
c
2、输出
d
e
f
3、说明
查询节点为c,其下层节点包括d和e,d的下层节点为f。按字典序输出为d, e, f。
五、解题思路
1、为什么采用深度优先搜索DFS?
DFS 适合树形结构的遍历,能够递归地查找所有下层节点,确保不遗漏任何节点。
2、具体步骤:
- 输入解析:
- 读取行数:首先读取输入的第一行,获取节点对的数量n。
- 读取父子节点关系:接下来读取n行,每行包含一个子节点和其对应的父节点,用空格分隔。例如,b a表示节点b的父节点是a。
- 读取查询节点:最后读取一行,获取需要查询的节点名称。
- 构建树结构:
- 邻接表表示法:使用一个HashMap<String, List>来表示树的结构,其中键是父节点,值是其子节点的列表。
- 键(父节点):表示树中的一个节点。
- 值(子节点列表):表示该父节点下的所有直接子节点。
- 构建过程:
- 遍历所有的父子节点对,将子节点添加到对应父节点的子节点列表中。
- 使用putIfAbsent方法确保每个父节点的子节点列表被正确初始化。
- 邻接表表示法:使用一个HashMap<String, List>来表示树的结构,其中键是父节点,值是其子节点的列表。
- 查找下层节点:
- 深度优先搜索(DFS):
- 从查询节点开始,递归地遍历所有子节点。
- 每访问一个子节点,将其加入结果列表。
- 继续递归查找该子节点的子节点,直到没有更多的下层节点。
- 实现细节:
- 定义一个递归方法findDescendants,接收树结构、当前节点和结果列表作为参数。
- 如果当前节点有子节点,遍历其子节点,加入结果列表,并递归调用findDescendants查找其子节点。
- 深度优先搜索(DFS):
- 排序输出:
- 字典序排序:使用Collections.sort()对结果列表进行字典序排序,确保输出的节点按照字母顺序排列。
- 输出结果:遍历排序后的列表,逐行输出每个下层节点。
3、时间复杂度
构建树结构:O(n),其中n是输入的父子节点对的数量。
查找下层节点(DFS):O(m),其中m是查询节点下层节点的数量。在最坏情况下,m = n。
排序:O(m log m),对找到的所有下层节点进行字典序排序。
4、空间复杂度
树结构存储:O(n),用于存储所有父子节点关系。
结果列表:O(m),用于存储所有下层节点。
六、Python算法源码
# 递归查找所有子节点
def find_descendants(tree, node, result):
if node in tree: # 检查节点是否在树中
for child in tree[node]: # 遍历当前节点的所有子节点
result.append(child) # 将子节点添加到结果列表中
find_descendants(tree, child, result) # 递归查找子节点
def main():
n = int(input()) # 读取输入的行数
tree = {} # 创建一个字典来存储树结构
# 读取所有父子节点关系
for _ in range(n):
line = input().split()
child, parent = line[0], line[1]
# 将子节点添加到父节点的子节点列表中
if parent not in tree:
tree[parent] = []
tree[parent].append(child)
query_node = input() # 读取查询的节点
descendants = [] # 存储所有下层节点的列表
find_descendants(tree, query_node, descendants) # 查找下层节点
descendants.sort() # 对结果进行字典序排序
# 打印结果
for descendant in descendants:
print(descendant)
if __name__ == "__main__":
main()
七、JavaScript算法源码
// 递归查找所有子节点
function findDescendants(tree, node, result) {
if (tree.hasOwnProperty(node)) { // 检查节点是否在树中
tree[node].forEach(function(child) { // 遍历当前节点的所有子节点
result.push(child); // 将子节点添加到结果列表中
findDescendants(tree, child, result); // 递归查找子节点
});
}
}
function main() {
const input = require('readline-sync'); // 引入同步输入模块
const n = parseInt(input.question()); // 读取输入的行数
const tree = {}; // 创建一个对象来存储树结构
// 读取所有父子节点关系
for (let i = 0; i < n; i++) {
const line = input.question().split(" ");
const child = line[0];
const parent = line[1];
// 将子节点添加到父节点的子节点列表中
if (!tree.hasOwnProperty(parent)) {
tree[parent] = [];
}
tree[parent].push(child);
}
const queryNode = input.question(); // 读取查询的节点
const descendants = []; // 存储所有下层节点的列表
findDescendants(tree, queryNode, descendants); // 查找下层节点
descendants.sort(); // 对结果进行字典序排序
// 打印结果
descendants.forEach(function(descendant) {
console.log(descendant);
});
}
main();
八、C算法源码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义树结构的节点
typedef struct Node {
char child[20];
struct Node* next;
} Node;
// 递归查找所有子节点
void find_descendants(Node* tree[], char* node, char result[][20], int* count) {
int idx = node[0] - 'A'; // 使用字符转换为索引
Node* current = tree[idx];
while (current != NULL) {
strcpy(result[*count], current->child); // 将子节点添加到结果数组中
(*count)++;
find_descendants(tree, current->child, result, count); // 递归查找子节点
current = current->next;
}
}
int compare(const void* a, const void* b) {
return strcmp((char*)a, (char*)b); // 用于排序的比较函数
}
int main() {
int n;
scanf("%d", &n); // 读取输入的行数
getchar(); // 读取换行符
// 创建树结构
Node* tree[26] = { NULL };
// 读取所有父子节点关系
for (int i = 0; i < n; i++) {
char child[20], parent[20];
scanf("%s %s", child, parent);
getchar(); // 读取换行符
// 将子节点添加到父节点的子节点列表中
int idx = parent[0] - 'A';
Node* new_node = (Node*)malloc(sizeof(Node));
strcpy(new_node->child, child);
new_node->next = tree[idx];
tree[idx] = new_node;
}
char query_node[20];
scanf("%s", query_node); // 读取查询的节点
char descendants[100][20]; // 存储所有下层节点
int count = 0;
find_descendants(tree, query_node, descendants, &count); // 查找下层节点
qsort(descendants, count, sizeof(descendants[0]), compare); // 对结果进行字典序排序
// 打印结果
for (int i = 0; i < count; i++) {
printf("%s\n", descendants[i]);
}
return 0;
}
九、C++算法源码
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
// 递归查找所有子节点
void findDescendants(map<string, vector<string>>& tree, const string& node, vector<string>& result) {
if (tree.find(node) != tree.end()) { // 检查节点是否在树中
for (const string& child : tree[node]) { // 遍历当前节点的所有子节点
result.push_back(child); // 将子节点添加到结果列表中
findDescendants(tree, child, result); // 递归查找子节点
}
}
}
int main() {
int n;
cin >> n; // 读取输入的行数
cin.ignore(); // 忽略换行符
map<string, vector<string>> tree; // 创建一个map来存储树结构
// 读取所有父子节点关系
for (int i = 0; i < n; i++) {
string child, parent;
cin >> child >> parent;
// 将子节点添加到父节点的子节点列表中
tree[parent].push_back(child);
}
string queryNode;
cin >> queryNode; // 读取查询的节点
vector<string> descendants; // 存储所有下层节点的列表
findDescendants(tree, queryNode, descendants); // 查找下层节点
sort(descendants.begin(), descendants.end()); // 对结果进行字典序排序
// 打印结果
for (const string& descendant : descendants) {
cout << descendant << endl;
}
return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。