华为OD机试 - 创建二叉树(Python/JS/C/C++ 2024 E卷 200分)

在这里插入图片描述

华为OD机试 2024E卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

请按下列描述构建一颗二叉树 Q,并返回该树的根节点:

1、先创建值为 0 的根结点,根节点 Q 在第 0 层;
2、然后根据 operations 依次添加节点:operations[i] = [height, index] 表示对第 height 层的第 index 个节点 node,添加值为 i 的子节点:

  • 若 node 无【左子节点】,则添加;
  • 若 node 有【左子节点】但是没有【右子节点】,则添加右子节点;
  • 若无可添加的子节点,则返回错误。

height, index 均为 0 开始计数; index 依存于节点的创建顺序。

注意:

  • 输入用例保证每次操作对应的节点已存在;
  • 控制台输出的内容是根据返回的树根节点,按层序遍历 Q 二叉树打印的结果。

二、输入描述

operations

三、输出描述

根据返回的树根节点,按照层序遍历 Q 二叉树打印的结果

备注

1 <= operations.length <= 100
operations[i].length == 2
0 <= operations[i][0] < 100
0 <= operations[i][1] < 100

四、测试用例

1、输入

[[0, 0], [0, 0], [1, 1], [1, 0], [0, 0]]

2、输出

[-1, 0, 1, 3, null, 2]

3、说明

首个值是根节点的值,也是返回值;
null 表示是空节点,此特殊层序遍历会遍历有值节点的 null 子节点

五、解题思路

1、问题分析

给定一系列操作,每个操作由两个整数 [height, index] 组成,表示在二叉树的第 height 层的第 index 个节点上添加一个子节点,子节点的值为操作的顺序索引 i。具体添加规则如下:

  1. 如果目标节点没有左子节点,则添加为左子节点。
  2. 如果目标节点已有左子节点但没有右子节点,则添加为右子节点。
  3. 如果目标节点的左右子节点都已存在,则返回错误(但题目保证输入操作都是有效的,可以添加节点)。

构建完二叉树后,进行层序遍历(广度优先遍历),并按照题目要求输出结果,空缺的节点用 null 表示。

2、具体步骤

  1. 初始化根节点:
    • 创建根节点,值为 -1(根据测试用例)。
    • 将根节点放入一个列表中,表示第0层。
  2. 构建树的层级结构:
    • 使用一个二维列表 treeLevels,其中 treeLevels[h] 表示第 h 层的所有节点。
    • 初始时,treeLevels[0] 只包含根节点。
  3. 处理每个操作:
    • 遍历每个操作 [height, index]。
    • 根据 height 和 index 找到目标父节点 parentNode。
    • 创建一个新的子节点,值为当前操作的索引 i。
    • 根据父节点的现有子节点情况,添加为左子节点或右子节点,并将新节点添加到 treeLevels[h + 1] 中对应层。
  4. 层序遍历:
    • 使用队列进行广度优先遍历。
    • 遍历过程中记录每个节点的值,如果节点为空,则记录 null。
    • 最后移除结果列表末尾多余的 null 值。
  5. 输出结果:
    • 将结果列表转换为字符串形式,按照题目要求的格式输出。

六、Python算法源码

import sys
import json
from collections import deque

# 定义二叉树的节点结构
class Node:
    def __init__(self, value):
        self.value = value          # 节点的值
        self.left = None            # 左子节点
        self.right = None           # 右子节点

def build_binary_tree(operations):
    # 初始化根节点,值为 -1
    root = Node(-1)
    
    # 使用列表存储每一层的节点,tree_levels[h] 表示第 h 层的节点列表
    tree_levels = []
    tree_levels.append([root])   # 第0层只有根节点
    
    # 遍历每个操作,依次添加节点
    for i, operation in enumerate(operations):
        height, index = operation  # 获取操作的高度和索引
        
        # 如果当前层级的列表不足以包含目标高度的下一层,则添加新的层
        while len(tree_levels) <= height + 1:
            tree_levels.append([])
        
        # 获取目标父节点
        parent_node = tree_levels[height][index]
        
        # 创建新的子节点,值为操作的索引 i
        child_node = Node(i)
        
        # 如果父节点没有左子节点,则添加为左子节点
        if parent_node.left is None:
            parent_node.left = child_node
        # 否则,如果父节点没有右子节点,则添加为右子节点
        elif parent_node.right is None:
            parent_node.right = child_node
        else:
            # 按题目保证,这种情况不会发生
            raise Exception("父节点的左右子节点都已存在,无法添加新的子节点")
        
        # 将新节点添加到对应层级的列表中
        tree_levels[height + 1].append(child_node)
    
    # 进行层序遍历,记录节点值
    result = []
    queue = deque()
    queue.append(root)  # 从根节点开始
    
    while queue:
        current_node = queue.popleft()  # 取出队首节点
        
        if current_node is not None:
            result.append(current_node.value)  # 记录节点的值
            queue.append(current_node.left)     # 添加左子节点到队列
            queue.append(current_node.right)    # 添加右子节点到队列
        else:
            result.append(None)                  # 记录为空节点
    
    # 移除结果列表末尾的多余 None 值
    while result and result[-1] is None:
        result.pop()
    
    # 将结果列表转换为字符串格式
    result_str = '[' + ', '.join(['null' if x is None else str(x) for x in result]) + ']'
    return result_str

def main():
    # 读取标准输入中的一行字符串
    input_line = sys.stdin.readline().strip()
    
    # 解析输入字符串为二维整数数组
    operations = json.loads(input_line)
    
    # 构建二叉树并获取层序遍历结果
    output = build_binary_tree(operations)
    
    # 输出结果
    print(output)

if __name__ == "__main__":
    main()

七、JavaScript算法源码

// 定义二叉树的节点结构
class Node {
    constructor(value) {
        this.value = value;      // 节点的值
        this.left = null;        // 左子节点
        this.right = null;       // 右子节点
    }
}

// 构建二叉树并返回层序遍历结果的字符串表示
function buildBinaryTree(operations) {
    // 初始化根节点,值为 -1
    const root = new Node(-1);
    
    // 使用数组存储每一层的节点,treeLevels[h] 表示第 h 层的节点列表
    const treeLevels = [];
    treeLevels.push([root]);   // 第0层只有根节点
    
    // 遍历每个操作,依次添加节点
    operations.forEach((operation, i) => {
        const height = operation[0];  // 获取操作的高度
        const index = operation[1];   // 获取操作的索引
        
        // 如果当前层级的列表不足以包含目标高度的下一层,则添加新的层
        while (treeLevels.length <= height + 1) {
            treeLevels.push([]);
        }
        
        // 获取目标父节点
        const parentNode = treeLevels[height][index];
        
        // 创建新的子节点,值为操作的索引 i
        const childNode = new Node(i);
        
        // 如果父节点没有左子节点,则添加为左子节点
        if (parentNode.left === null) {
            parentNode.left = childNode;
        }
        // 否则,如果父节点没有右子节点,则添加为右子节点
        else if (parentNode.right === null) {
            parentNode.right = childNode;
        }
        else {
            // 按题目保证,这种情况不会发生
            throw new Error("父节点的左右子节点都已存在,无法添加新的子节点");
        }
        
        // 将新节点添加到对应层级的列表中
        treeLevels[height + 1].push(childNode);
    });
    
    // 进行层序遍历,记录节点值
    const result = [];
    const queue = [];
    queue.push(root);  // 从根节点开始
    
    while (queue.length > 0) {
        const currentNode = queue.shift();  // 取出队首节点
        
        if (currentNode !== null) {
            result.push(currentNode.value);   // 记录节点的值
            queue.push(currentNode.left);     // 添加左子节点到队列
            queue.push(currentNode.right);    // 添加右子节点到队列
        }
        else {
            result.push(null);                 // 记录为空节点
        }
    }
    
    // 移除结果数组末尾的多余 null 值
    while (result.length > 0 && result[result.length - 1] === null) {
        result.pop();
    }
    
    // 将结果数组转换为字符串格式
    const resultStr = '[' + result.map(x => x === null ? 'null' : x.toString()).join(', ') + ']';
    return resultStr;
}

// 主函数,读取输入并输出结果
function main() {
    const fs = require('fs');
    const input = fs.readFileSync('/dev/stdin', 'utf8').trim();
    
    // 解析输入字符串为二维整数数组
    const operations = JSON.parse(input);
    
    // 构建二叉树并获取层序遍历结果
    const output = buildBinaryTree(operations);
    
    // 输出结果
    console.log(output);
}

main();

八、C算法源码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 定义二叉树的节点结构
typedef struct Node {
    int value;              // 节点的值
    struct Node* left;      // 左子节点
    struct Node* right;     // 右子节点
} Node;

// 创建新的节点
Node* createNode(int value) {
    Node* newNode = (Node*)malloc(sizeof(Node)); // 分配内存
    newNode->value = value;                      // 设置节点值
    newNode->left = NULL;                        // 初始化左子节点为空
    newNode->right = NULL;                       // 初始化右子节点为空
    return newNode;                              // 返回新节点
}

// 动态数组结构,用于存储每一层的节点
typedef struct {
    Node*** levels;   // 二维指针,levels[h][i] 表示第 h 层的第 i 个节点
    int* counts;      // 每一层的节点数量
    int capacity;     // 当前层数
} TreeLevels;

// 初始化 TreeLevels 结构
TreeLevels* initTreeLevels(int initial_capacity) {
    TreeLevels* tl = (TreeLevels*)malloc(sizeof(TreeLevels));
    tl->levels = (Node***)malloc(sizeof(Node**) * initial_capacity);
    tl->counts = (int*)malloc(sizeof(int) * initial_capacity);
    for(int i = 0; i < initial_capacity; i++) {
        tl->levels[i] = NULL;
        tl->counts[i] = 0;
    }
    tl->capacity = initial_capacity;
    return tl;
}

// 添加节点到指定层
void addNodeToLevel(TreeLevels* tl, int level, Node* node) {
    if(level >= tl->capacity) {
        // 扩展层级容量
        tl->levels = (Node***)realloc(tl->levels, sizeof(Node**) * (level + 1));
        tl->counts = (int*)realloc(tl->counts, sizeof(int) * (level + 1));
        for(int i = tl->capacity; i <= level; i++) {
            tl->levels[i] = NULL;
            tl->counts[i] = 0;
        }
        tl->capacity = level + 1;
    }
    // 添加节点到指定层
    tl->levels[level] = (Node**)realloc(tl->levels[level], sizeof(Node*) * (tl->counts[level] + 1));
    tl->levels[level][tl->counts[level]] = node;
    tl->counts[level]++;
}

// 层序遍历并获取结果字符串
char* levelOrderTraversal(Node* root) {
    // 使用动态数组模拟队列
    Node** queue = (Node**)malloc(sizeof(Node*) * 1000);
    int front = 0, rear = 0;
    
    // 结果数组,初始化为全零
    int* result = (int*)malloc(sizeof(int) * 1000);
    int result_size = 0;
    int null_marker = 1001; // 特殊标记,表示 null
    
    // 入队根节点
    queue[rear++] = root;
    
    while(front < rear) {
        Node* current = queue[front++];
        if(current != NULL) {
            result[result_size++] = current->value;
            queue[rear++] = current->left;
            queue[rear++] = current->right;
        }
        else {
            result[result_size++] = null_marker;
        }
    }
    
    // 移除结果末尾的 null
    while(result_size > 0 && result[result_size - 1] == null_marker) {
        result_size--;
    }
    
    // 构建结果字符串
    char* res_str = (char*)malloc(sizeof(char) * 5000);
    strcpy(res_str, "[");
    for(int i = 0; i < result_size; i++) {
        if(result[i] == null_marker) {
            strcat(res_str, "null");
        }
        else {
            char num_str[12];
            sprintf(num_str, "%d", result[i]);
            strcat(res_str, num_str);
        }
        if(i != result_size -1) {
            strcat(res_str, ", ");
        }
    }
    strcat(res_str, "]");
    
    // 释放内存
    free(queue);
    free(result);
    
    return res_str;
}

int main() {
    // 读取输入
    char input_line[1000];
    fgets(input_line, sizeof(input_line), stdin);
    
    // 解析输入,假设输入格式为 [[0,0], [0,0], [1,1], [1,0], [0,0]]
    // 先统计操作数量
    int operations[100][2];
    int op_count = 0;
    char* token = strtok(input_line, "[] ,");
    while(token != NULL) {
        operations[op_count][op_count %2] = atoi(token);
        op_count++;
        token = strtok(token, "[] ,");
    }
    op_count /=2;
    
    // 转换为二维数组
    int num_operations = op_count;
    int ops[100][2];
    for(int i = 0; i < num_operations; i++) {
        ops[i][0] = operations[2*i][0];
        ops[i][1] = operations[2*i +1][0];
    }
    
    // 初始化根节点
    Node* root = createNode(-1);
    
    // 初始化 TreeLevels 结构
    TreeLevels* tree_levels = initTreeLevels(10);
    addNodeToLevel(tree_levels, 0, root); // 第0层添加根节点
    
    // 处理每个操作
    for(int i = 0; i < num_operations; i++) {
        int height = ops[i][0];
        int index = ops[i][1];
        
        // 获取父节点
        Node* parent = tree_levels->levels[height][index];
        
        // 创建子节点
        Node* child = createNode(i);
        
        // 添加子节点
        if(parent->left == NULL) {
            parent->left = child;
        }
        else if(parent->right == NULL) {
            parent->right = child;
        }
        else {
            // 根据题目保证,不会发生
            printf("Error: 父节点的左右子节点都已存在。\n");
            return 1;
        }
        
        // 添加子节点到下一层
        addNodeToLevel(tree_levels, height +1, child);
    }
    
    // 进行层序遍历并获取结果
    char* output = levelOrderTraversal(root);
    
    // 输出结果
    printf("%s\n", output);
    
    // 释放内存
    free(output);
    // 此处省略其他内存释放,为简化代码
    
    return 0;
}

九、C++算法源码

#include <bits/stdc++.h>
using namespace std;

// 定义二叉树的节点结构
struct Node {
    int value;          // 节点的值
    Node* left;         // 左子节点
    Node* right;        // 右子节点
    
    Node(int val) : value(val), left(nullptr), right(nullptr) {}
};

// 构建二叉树并返回层序遍历结果的字符串表示
string buildBinaryTree(vector<vector<int>> operations) {
    // 初始化根节点,值为 -1
    Node* root = new Node(-1);
    
    // 使用vector存储每一层的节点,treeLevels[h] 表示第 h 层的节点列表
    vector<vector<Node*>> treeLevels;
    treeLevels.emplace_back(); // 添加第0层
    treeLevels[0].push_back(root); // 第0层只有根节点
    
    // 遍历每个操作,依次添加节点
    for(int i = 0; i < operations.size(); i++) {
        int height = operations[i][0];  // 获取操作的高度
        int index = operations[i][1];   // 获取操作的索引
        
        // 如果当前层级的列表不足以包含目标高度的下一层,则添加新的层
        while(treeLevels.size() <= height + 1) {
            treeLevels.emplace_back();
        }
        
        // 获取目标父节点
        Node* parentNode = treeLevels[height][index];
        
        // 创建新的子节点,值为操作的索引 i
        Node* childNode = new Node(i);
        
        // 如果父节点没有左子节点,则添加为左子节点
        if(parentNode->left == nullptr) {
            parentNode->left = childNode;
        }
        // 否则,如果父节点没有右子节点,则添加为右子节点
        else if(parentNode->right == nullptr) {
            parentNode->right = childNode;
        }
        else {
            // 根据题目保证,不会发生
            throw runtime_error("父节点的左右子节点都已存在,无法添加新的子节点");
        }
        
        // 将新节点添加到对应层级的列表中
        treeLevels[height + 1].push_back(childNode);
    }
    
    // 进行层序遍历,记录节点值
    vector<string> result;
    queue<Node*> q;
    q.push(root); // 从根节点开始
    
    while(!q.empty()) {
        Node* current = q.front();
        q.pop();
        
        if(current != nullptr) {
            result.push_back(to_string(current->value));  // 记录节点的值
            q.push(current->left);                       // 添加左子节点到队列
            q.push(current->right);                      // 添加右子节点到队列
        }
        else {
            result.push_back("null");                     // 记录为空节点
        }
    }
    
    // 移除结果末尾的多余 "null" 值
    while(!result.empty() && result.back() == "null") {
        result.pop_back();
    }
    
    // 构建结果字符串
    string res_str = "[";
    for(int i = 0; i < result.size(); i++) {
        res_str += result[i];
        if(i != result.size() -1) {
            res_str += ", ";
        }
    }
    res_str += "]";
    
    return res_str;
}

int main(){
    // 读取输入
    string input_line;
    getline(cin, input_line);
    
    // 解析输入字符串为二维整数数组
    // 使用字符串流和手动解析
    vector<vector<int>> operations;
    int num;
    vector<int> current_op;
    for(char c : input_line){
        if(c == '['){
            current_op.clear();
        }
        else if(c == ',' || c == ']'){
            if(!current_op.empty()){
                operations.emplace_back(current_op);
                current_op.clear();
            }
        }
        else if(isdigit(c) || c == '-'){
            string num_str;
            while(isdigit(c) || c == '-'){
                num_str += c;
                // 读取下一个字符
                size_t pos = input_line.find(c);
                if(pos == string::npos || pos +1 >= input_line.size()) break;
                c = input_line[pos +1];
            }
            current_op.push_back(stoi(num_str));
        }
    }
    
    // 构建二叉树并获取层序遍历结果
    string output = buildBinaryTree(operations);
    
    // 输出结果
    cout << output << 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、付费专栏及课程。

余额充值