华为OD机试 - 树状结构查询 - 深度优先搜索DFS(Python/JS/C/C++ 2024 E卷 200分)

在这里插入图片描述

华为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、具体步骤:

  1. 输入解析:
    • 读取行数:首先读取输入的第一行,获取节点对的数量n。
    • 读取父子节点关系:接下来读取n行,每行包含一个子节点和其对应的父节点,用空格分隔。例如,b a表示节点b的父节点是a。
    • 读取查询节点:最后读取一行,获取需要查询的节点名称。
  2. 构建树结构:
    • 邻接表表示法:使用一个HashMap<String, List>来表示树的结构,其中键是父节点,值是其子节点的列表。
      • 键(父节点):表示树中的一个节点。
      • 值(子节点列表):表示该父节点下的所有直接子节点。
    • 构建过程:
      • 遍历所有的父子节点对,将子节点添加到对应父节点的子节点列表中。
      • 使用putIfAbsent方法确保每个父节点的子节点列表被正确初始化。
  3. 查找下层节点:
    • 深度优先搜索(DFS):
      • 从查询节点开始,递归地遍历所有子节点。
      • 每访问一个子节点,将其加入结果列表。
      • 继续递归查找该子节点的子节点,直到没有更多的下层节点。
    • 实现细节:
      • 定义一个递归方法findDescendants,接收树结构、当前节点和结果列表作为参数。
      • 如果当前节点有子节点,遍历其子节点,加入结果列表,并递归调用findDescendants查找其子节点。
  4. 排序输出:
    • 字典序排序:使用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在线答疑。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值