华为OD机试新系统真题【盘丝洞破阵寻珠】

盘丝洞破阵寻珠(C/C++/Py/Java/Js/Go)题解

华为OD机试新系统真题 华为OD上机考试新系统真题 6月28号 200分题型

华为OD机试新系统真题目录点击查看: 华为OD机试新系统真题题库目录|机考题库 + 算法考点详解

题目内容

天命人深入盘丝洞,洞内布满了蜘蛛精设下的迷阵。整座洞穴呈二叉树结构 ,每个结点是一间石室,石室中藏有灵气结晶(整数,可正可负,零值视为非负)。

天命人从根石室 出发,寻找通往叶子石室 的路径收集灵气。但盘丝洞有毒瘴禁制 :路径上不允许出现连续两个或以上灵气值为负 的石室。

叶子石室 的定义:左右子结点均为空的结点。

请实现一个函数,在一遍遍历中同时计算以下三个指标:

  1. 合法路径的最大灵气和
  2. 是否存在合法路径和 ≥ \ge ≥ 给定阈值
  3. 合法路径的总数

输入描述

二叉树根节点 root \text{root} root,整数 threshold \text{threshold} threshold

输出描述

包含 3 3 3 个整数的数组 [max_val,has_path_ge, count]

  • max_val:合法路径的最大灵气和,无合法路径返回 − 2147483648 -2147483648 −2147483648
  • has_path_ge:存在合法路径和 ≥ threshold \ge \text{threshold} ≥threshold 返回 1 1 1,否则返回 0 0 0
  • count:合法路径的总数

二叉树输入格式说明:

二叉树采用层次遍历方式序列化表示:

  • 按从上到下、从左到右的顺序依次列出每个节点的值

  • \# # 表示该位置为空节点(无子节点)

  • 空树用 { } \{\} {} 或 { # } \{\#\} {#} 表示
    示例: { 10 , − 5 , 20 , # , 8 , − 6 , 15 } \{10,-5,20,\#,8,-6,15\} {10,−5,20,#,8,−6,15} 表示:

    复制代码
      10
     /  \
    -5   20
     \   / \ 
      8 -6  15
  • 解析规则:根节点为 10 10 10,左子节点 − 5 -5 −5(其左子为空 # \# #,右子为 8 8 8),右子节点 20 20 20(左子 − 6 -6 −6,右子 15 15 15)。

数据范围:

  • 节点数: 0 ≤ n ≤ 10 5 0 \le n \le 10^5 0≤n≤105
  • 节点值: − 100 ≤ val ≤ 100 -100 \le \text{val} \le 100 −100≤val≤100
  • 树深度: ≤ 10 4 \le 10^4 ≤104
  • 阈值: − 10 9 ≤ threshold ≤ 10 9 -10^9 \le \text{threshold} \le 10^9 −109≤threshold≤109
  • 空树说明:当 n = 0 n = 0 n=0 时返回 − 2147483648 , 0 , 0 -2147483648, 0, 0 −2147483648,0,0

样例1

输入

复制代码
10,-5,20,#,8,-6,15
40

输出

复制代码
45 1 3

说明

二叉树结构:

复制代码
       10
      /   \
     -5    20
      \    / \
       8  -6  15

从根到叶子共 3 3 3 条路径:

  • 10 → − 5 → 8 10 \to -5 \to 8 10→−5→8,和 = 13 13 13,负节点不连续,合法
  • 10 → 20 → − 6 10 \to 20 \to -6 10→20→−6,和 = 24 24 24,负节点不连续,合法
  • 10 → 20 → 15 10 \to 20 \to 15 10→20→15,和 = 45 45 45,无负节点,合法
    最大合法路径和 = 45 45 45,存在路径和 ≥ 40 \ge 40 ≥40,合法路径数 = 3 3 3。

样例2

输入

复制代码
-5,-3,#,#,-7
-100

输出

复制代码
-2147483648 0 0

说明

二叉树结构:

复制代码
    -5
    /
   -3
    \
     -7

从根到叶子仅 1 1 1 条路径:

  • − 5 → − 3 → − 7 -5 \to -3 \to -7 −5→−3→−7,和 = − 15 -15 −15,但 − 5 -5 −5 与 − 3 -3 −3 为连续负节点,路径非法。

样例3

输入

复制代码
5,-3,#,#,8,-2,#,#,10
18

输出

复制代码
18 1 1

说明

二叉树结构:

复制代码
       5
      /
     -3
      \
       8
       /
      -2
       \
       10

从根到叶子仅 1 1 1 条路径:

  • 5 → − 3 → 8 → − 2 → 10 5 \to -3 \to 8 \to -2 \to 10 5→−3→8→−2→10,和 = 18 18 18,负节点 − 3 -3 −3 与 − 2 -2 −2 之间隔了正节点 8 8 8,不连续,路径合法。
    最大合法路径和 = 18 18 18,存在路径和 ≥ 18 \ge 18 ≥18,合法路径数 = 1 1 1。

题解

思路:DFS + BFS

  1. 先通过BFS进行二叉树还原。
  2. 接下来从二叉树根节点进行递归记录合法路径数量以及最大合法路径和,递归过程中需要保存之前路径的总和sum 、 连续负数数量 negativeCount ,每一层处理逻辑如下
    1. 根据当前value的值,更新curNegativeCount,
      • 如果value < 0: curNegativeCount = negativeCount + 1
      • 如果value >= 0: curNegativeCount = 0
    2. 如果curNegativeCount >= 2则说明路径非法,终止递归
    3. 更新路径总和curSum = sum + value
    4. 如果当前节点为叶子节点,增加合法路径数目和尝试更新合法路径最大值。
    5. 非叶子节点使用curSum和curNegativeCount继续往下递归
  3. 通过递归可以获取到合法路径数量和最大合法路径总和。通过这些数据足以构造出题目要求的最终结果。

C++

cpp 复制代码
#include<bits/stdc++.h>
#include <queue>
#include <vector>
using namespace std;


const int INT_MIN_VAL = -2147483648;


int legalCount = 0;
int maxValue = INT_MIN_VAL;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;

    TreeNode(int val):val(val) {
        left = nullptr;
        right = nullptr;
    }
    
};




// 通用 切割函数 函数 将字符串str根据delimiter进行切割
vector<string> split(const string& str, const string& delimiter) {
    vector<string> result;
    size_t start = 0;
    size_t end = str.find(delimiter);
    while (end != string::npos) {
        result.push_back(str.substr(start, end - start));
        start = end + delimiter.length();
        end = str.find(delimiter, start);
    }
    // 添加最后一个部分
    result.push_back(str.substr(start));
    return result;
}

// sum之前路径的和  negativeCount 连续负数个数
void dfs(TreeNode* root, int sum, int negativeCount) {
    int value = root->val;
    int curNegativeCount = negativeCount;
    // 增加连续非负
    if (value < 0) {
        curNegativeCount++;
    // 中断连续非负    
    } else {
       curNegativeCount = 0; 
    }
    // 路径非法
    if (curNegativeCount >= 2) {
        return;
    }

    int newSum = sum + value;
    // 叶子节点
    if (root->left == nullptr && root->right == nullptr) {
        maxValue = max(maxValue, newSum);
        legalCount += 1;
        return;
    }
    
    if (root->left != nullptr) {
        dfs(root->left, newSum, curNegativeCount);
    }
    if (root->right != nullptr) {
        dfs(root->right, newSum, curNegativeCount);
    }
}


vector<int> solve(TreeNode* root, int threshold) {
    if (root == nullptr) {
        return {INT_MIN_VAL, 0, 0};
    }
    dfs(root, 0, 0);
    int has_path_ge = 0;
    if (legalCount > 0 && maxValue >= threshold) {
        has_path_ge = 1;
    }
    return {maxValue, has_path_ge, legalCount};
}


int main() {
    string input;
    getline(cin, input);
    
    int threshold;
    cin >> threshold;
    
    
    
    // 还原二叉树
    TreeNode* root = nullptr;
    

    if (!input.empty()) {
        vector<string> node = split(input, ",");
        int n = node.size();
        // 首个非空节点
        if (node[0] != "#") {
            int index = 0;
            root = new TreeNode(stoi(node[0]));
            // BFS还原二叉树
            queue<TreeNode*> q;
            q.push(root);
            index++;
            while (!q.empty() && index < n) {
                TreeNode* cur = q.front();
                q.pop();
                string left = "#";
                string right = "#";
                // 左节点
                if (index < n) {
                    left = node[index];
                    index++;
                }
                // 右节点
                if (index < n) {
                    right = node[index];
                    index++;
                }
                if (left != "#") {
                    TreeNode* leftChild = new TreeNode(stoi(left));
                    cur->left = leftChild;
                    q.push(leftChild);
                }
                if (right != "#") {
                    TreeNode* rightChild = new TreeNode(stoi(right));
                    cur->right = rightChild;
                    q.push(rightChild);
                }            
            }
        }    
    }

    vector<int> res = solve(root, threshold);
    cout << res[0] << " " << res[1] << " " << res[2];
    return 0;
}

JAVA

java 复制代码
import java.util.*;

public class Main {

    static class TreeNode {
        int val;
        TreeNode left, right;
        TreeNode(int v) { val = v; }
    }

    static int legalCount = 0;
    static int maxValue = Integer.MIN_VALUE;

    // dfs:sum之前路径的和  negativeCount 连续负数个数
    static void dfs(TreeNode root, int sum, int negativeCount) {

        int value = root.val;
        int curNegativeCount = negativeCount;

        // 增加连续非负
        if (value < 0) {
            curNegativeCount++;
        // 中断连续非负
        } else {
            curNegativeCount = 0;
        }

        // 路径非法
        if (curNegativeCount >= 2) return;

        int newSum = sum + value;

        // 叶子节点
        if (root.left == null && root.right == null) {
            maxValue = Math.max(maxValue, newSum);
            legalCount++;
            return;
        }

        if (root.left != null) dfs(root.left, newSum, curNegativeCount);
        if (root.right != null) dfs(root.right, newSum, curNegativeCount);
    }

    static int[] solve(TreeNode root, int threshold) {
        if (root == null) return new int[]{Integer.MIN_VALUE, 0, 0};

        dfs(root, 0, 0);

        int has_path_ge = 0;
        if (legalCount > 0 && maxValue >= threshold) {
            has_path_ge = 1;
        }

        return new int[]{maxValue, has_path_ge, legalCount};
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        String input = sc.nextLine();
        int threshold = sc.nextInt();

        TreeNode root = null;

        if (input.length() > 0) {
            String[] node = input.split(",");

            // 还原二叉树
            if (!node[0].equals("#")) {
                root = new TreeNode(Integer.parseInt(node[0]));
                Queue<TreeNode> q = new LinkedList<>();
                q.add(root);

                int index = 1;

                // BFS还原二叉树
                while (!q.isEmpty() && index < node.length) {
                    TreeNode cur = q.poll();

                    String left = "#";
                    String right = "#";

                    // 左节点
                    if (index < node.length) left = node[index++];
                    // 右节点
                    if (index < node.length) right = node[index++];

                    if (!left.equals("#")) {
                        cur.left = new TreeNode(Integer.parseInt(left));
                        q.add(cur.left);
                    }

                    if (!right.equals("#")) {
                        cur.right = new TreeNode(Integer.parseInt(right));
                        q.add(cur.right);
                    }
                }
            }
        }

        int[] res = solve(root, threshold);
        System.out.println(res[0] + " " + res[1] + " " + res[2]);
    }
}

Python

python 复制代码
import sys
from collections import deque
sys.setrecursionlimit(10 ** 6)

class TreeNode:
    def __init__(self, v):
        self.val = v
        self.left = None
        self.right = None

legalCount = 0
maxValue = -2147483648

# dfs:sum之前路径的和  negativeCount 连续负数个数
def dfs(root, sum_val, negativeCount):
    global legalCount, maxValue

    value = root.val
    curNegativeCount = negativeCount

    # 增加连续非负
    if value < 0:
        curNegativeCount += 1
    # 中断连续非负
    else:
        curNegativeCount = 0

    # 路径非法
    if curNegativeCount >= 2:
        return

    newSum = sum_val + value

    # 叶子节点
    if root.left is None and root.right is None:
        maxValue = max(maxValue, newSum)
        legalCount += 1
        return

    if root.left is not None:
        dfs(root.left, newSum, curNegativeCount)
    if root.right is not None:
        dfs(root.right, newSum, curNegativeCount)


def solve(root, threshold):
    global legalCount, maxValue

    if root is None:
        return [-2147483648, 0, 0]

    dfs(root, 0, 0)

    has_path_ge = 0
    if legalCount > 0 and maxValue >= threshold:
        has_path_ge = 1

    return [maxValue, has_path_ge, legalCount]



input_str = sys.stdin.readline().strip()
threshold = int(sys.stdin.readline())

root = None

if input_str:
    node = input_str.split(",")

    # 还原二叉树
    if node[0] != "#":
        root = TreeNode(int(node[0]))
        q = deque([root])
        index = 1

        # BFS还原二叉树
        while q and index < len(node):
            cur = q.popleft()

            left = "#"
            right = "#"

            # 左节点
            if index < len(node):
                left = node[index]
                index += 1

            # 右节点
            if index < len(node):
                right = node[index]
                index += 1

            if left != "#":
                cur.left = TreeNode(int(left))
                q.append(cur.left)

            if right != "#":
                cur.right = TreeNode(int(right))
                q.append(cur.right)

res = solve(root, threshold)
print(res[0], res[1], res[2])

JavaScript

js 复制代码
const readline = require("readline");

class TreeNode {
    constructor(val) {
        this.val = val;
        this.left = null;
        this.right = null;
    }
}

let legalCount = 0;
let maxValue = -2147483648;

// dfs:sum之前路径的和  negativeCount 连续负数个数
function dfs(root, sum, negativeCount) {
    let value = root.val;
    let curNegativeCount = negativeCount;

    // 增加连续非负
    if (value < 0) {
        curNegativeCount++;
    // 中断连续非负
    } else {
        curNegativeCount = 0;
    }

    // 路径非法
    if (curNegativeCount >= 2) return;

    let newSum = sum + value;

    // 叶子节点
    if (!root.left && !root.right) {
        maxValue = Math.max(maxValue, newSum);
        legalCount++;
        return;
    }

    if (root.left) {
        dfs(root.left, newSum, curNegativeCount);
    }
    if (root.right) {
        dfs(root.right, newSum, curNegativeCount);
    }
}

function solve(root, threshold) {
    if (!root) return [-2147483648, 0, 0];

    dfs(root, 0, 0);

    let has_path_ge = 0;
    if (legalCount > 0 && maxValue >= threshold) {
        has_path_ge = 1;
    }

    return [maxValue, has_path_ge, legalCount];
}

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

let lines = [];

rl.on("line", (line) => {
    lines.push(line.trim());
}).on("close", () => {

    let input = lines[0];
    let threshold = parseInt(lines[1]);

    let root = null;

    if (input.length > 0) {
        let node = input.split(",");

        // 还原二叉树
        if (node[0] !== "#") {
            root = new TreeNode(parseInt(node[0]));
            let q = [root];
            let index = 1;

            // BFS还原二叉树
            while (q.length && index < node.length) {
                let cur = q.shift();

                let left = "#";
                let right = "#";

                // 左节点
                if (index < node.length) {
                    left = node[index++];
                }

                // 右节点
                if (index < node.length) {
                    right = node[index++];
                }

                if (left !== "#") {
                    cur.left = new TreeNode(parseInt(left));
                    q.push(cur.left);
                }

                if (right !== "#") {
                    cur.right = new TreeNode(parseInt(right));
                    q.push(cur.right);
                }
            }
        }
    }

    let res = solve(root, threshold);
    console.log(res.join(" "));
});

Go

go 复制代码
package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

var legalCount int
var maxValue int

// dfs:sum之前路径的和  negativeCount 连续负数个数
func dfs(root *TreeNode, sum int, negativeCount int) {

    value := root.Val
    curNegativeCount := negativeCount

    // 增加连续非负
    if value < 0 {
        curNegativeCount++
    // 中断连续非负
    } else {
        curNegativeCount = 0
    }

    // 路径非法
    if curNegativeCount >= 2 {
        return
    }

    newSum := sum + value

    // 叶子节点
    if root.Left == nil && root.Right == nil {
        if newSum > maxValue {
            maxValue = newSum
        }
        legalCount++
        return
    }

    if root.Left != nil {
        dfs(root.Left, newSum, curNegativeCount)
    }
    if root.Right != nil {
        dfs(root.Right, newSum, curNegativeCount)
    }
}

// solve函数
func solve(root *TreeNode, threshold int) []int {
    maxValue = -2147483648
    legalCount = 0
    if root == nil {
        return []int{-2147483648, 0, 0}
    }

    dfs(root, 0, 0)

    hasPathGe := 0
    if legalCount > 0 && maxValue >= threshold {
        hasPathGe = 1
    }

    return []int{maxValue, hasPathGe, legalCount}
}

func main() {
    reader := bufio.NewReader(os.Stdin)

    input, _ := reader.ReadString('\n')
    input = strings.TrimSpace(input)

    thresholdStr, _ := reader.ReadString('\n')
    thresholdStr = strings.TrimSpace(thresholdStr)
    threshold, _ := strconv.Atoi(thresholdStr)

    var root *TreeNode

    if len(input) > 0 {

        node := strings.Split(input, ",")

        // 还原二叉树
        if node[0] != "#" {
            val, _ := strconv.Atoi(node[0])
            root = &TreeNode{Val: val}

            queue := []*TreeNode{root}
            index := 1

            // BFS还原二叉树
            for len(queue) > 0 && index < len(node) {
                cur := queue[0]
                queue = queue[1:]

                left := "#"
                right := "#"

                // 左节点
                if index < len(node) {
                    left = node[index]
                    index++
                }

                // 右节点
                if index < len(node) {
                    right = node[index]
                    index++
                }

                if left != "#" {
                    v, _ := strconv.Atoi(left)
                    cur.Left = &TreeNode{Val: v}
                    queue = append(queue, cur.Left)
                }

                if right != "#" {
                    v, _ := strconv.Atoi(right)
                    cur.Right = &TreeNode{Val: v}
                    queue = append(queue, cur.Right)
                }
            }
        }
    }

    res := solve(root, threshold)
    fmt.Println(res[0], res[1], res[2])
}

C语言

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>



typedef struct TreeNode {
    int val;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

int legalCount = 0;
int maxValue = -2147483648;

TreeNode* createNode(int v) {
    TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
    node->val = v;
    node->left = node->right = NULL;
    return node;
}

// dfs:sum之前路径的和  negativeCount 连续负数个数
void dfs(TreeNode* root, int sum, int negativeCount) {

    int value = root->val;
    int curNegativeCount = negativeCount;

    // 增加连续非负
    if (value < 0) {
        curNegativeCount++;
    // 中断连续非负
    } else {
        curNegativeCount = 0;
    }

    // 路径非法
    if (curNegativeCount >= 2) {
        return;
    }

    int newSum = sum + value;

    // 叶子节点
    if (root->left == NULL && root->right == NULL) {
        if (newSum > maxValue) {
            maxValue = newSum;
        }
        legalCount++;
        return;
    }

    if (root->left != NULL) {
        dfs(root->left, newSum, curNegativeCount);
    }
    if (root->right != NULL) {
        dfs(root->right, newSum, curNegativeCount);
    }
}

// 构建二叉树(BFS还原)
TreeNode* buildTree(char* input) {
    char* arr[1000100];
    int n = 0;

    char* token = strtok(input, ",");
    while (token != NULL) {
        arr[n++] = token;
        token = strtok(NULL, ",");
    }

    if (n == 0 || strcmp(arr[0], "#") == 0) {
        return NULL;
    }

    TreeNode* root = createNode(atoi(arr[0]));

    TreeNode* queue[1000100];
    int front = 0, rear = 0;

    queue[rear++] = root;

    int index = 1;

    // BFS还原二叉树
    while (front < rear && index < n) {
        TreeNode* cur = queue[front++];

        char* left = "#";
        char* right = "#";

        // 左节点
        if (index < n) {
            left = arr[index++];
        }

        // 右节点
        if (index < n) {
            right = arr[index++];
        }

        if (strcmp(left, "#") != 0) {
            TreeNode* ln = createNode(atoi(left));
            cur->left = ln;
            queue[rear++] = ln;
        }

        if (strcmp(right, "#") != 0) {
            TreeNode* rn = createNode(atoi(right));
            cur->right = rn;
            queue[rear++] = rn;
        }
    }

    return root;
}

// solve函数
int* solve(TreeNode* root, int threshold, int* outSize) {
    static int res[3];

    if (root == NULL) {
        res[0] = -2147483648;
        res[1] = 0;
        res[2] = 0;
        *outSize = 3;
        return res;
    }

    dfs(root, 0, 0);

    int hasPathGe = 0;
    if (legalCount > 0 && maxValue >= threshold) {
        hasPathGe = 1;
    }

    res[0] = maxValue;
    res[1] = hasPathGe;
    res[2] = legalCount;

    *outSize = 3;
    return res;
}

int main() {
    char input[1000000];
    fgets(input, sizeof(input), stdin);

    int threshold;
    scanf("%d", &threshold);

    input[strcspn(input, "\n")] = 0;

    TreeNode* root = buildTree(input);

    int size;
    int* res = solve(root, threshold, &size);

    printf("%d %d %d", res[0], res[1], res[2]);

    return 0;
}