当前位置: 首页 > news >正文

华为OD机试真题——二维伞的雨滴效应(2025A卷:200分)Java/python/JavaScript/C/C++/GO最佳实现

在这里插入图片描述

2025 A卷 200分 题型

本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式;
并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析;
本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分享》

华为OD机试真题《二维伞的雨滴效应》:


文章快捷目录

题目描述及说明

Java

python

JavaScript

C

GO

更多内容


题目名称:二维伞的雨滴效应


知识点:递归、二叉搜索树验证、逻辑处理
时间限制:1秒
空间限制:256MB
限定语言:不限


题目描述

普通的伞在二维平面世界中,左右两侧均有一条边,而两侧伞边最下面各有一个伞坠子。雨滴落到伞面后,逐步流到伞坠处,携带伞坠信息落到地面。现输入一串正整数数组序列(不含0,数组成员至少1个),要求:

  1. 判断该数组是否为二叉搜索树的前序遍历结果。若是,输出1;否则输出0。
  2. 若为二叉搜索树,输出左右伞坠信息(即树的最左端和最右端叶子节点值);若无左/右伞坠,则对应位置输出0。若非二叉搜索树,左右伞坠信息均返回0。

输入示例

8 3 1 6 4 7 10 14 13  

输出示例

1 1 13  

说明

  • 1表示是二叉搜索树前序遍历结果。
  • 1为左伞坠值(最左叶子节点值)。
  • 13为右伞坠值(最右叶子节点值)。

输入约束

  • 输入数组任意两个数字互不相同。
  • 数组长度最多1000,数值范围1~65535。

Java

问题分析

题目要求判断给定的正整数数组是否为二叉搜索树(BST)的前序遍历结果,并输出相应的结果。如果是BST,还需要找出最左和最右的叶子节点值(伞坠信息)。主要挑战在于如何高效验证前序遍历的正确性,并在验证的同时构建树结构以确定叶子节点。

解题思路

  1. 验证BST前序遍历

    • 递归检查数组是否符合BST前序遍历的结构。根节点后,找到第一个大于根的元素作为右子树的起点,确保右子树所有元素均大于根,左子树所有元素均小于根。
  2. 构建树结构

    • 如果验证通过,递归构建二叉树,以便后续查找叶子节点。
  3. 查找叶子节点

    • 前序遍历构建好的树,记录第一个和最后一个遇到的叶子节点值,即为最左和最右伞坠信息。

代码实现

import java.util.Scanner;public class Main {static int leftLeaf = 0;static int rightLeaf = 0;public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String input = scanner.nextLine();String[] parts = input.split(" ");int[] preorder = new int[parts.length];for (int i = 0; i < parts.length; i++) {preorder[i] = Integer.parseInt(parts[i]);}boolean isBST = verifyBST(preorder, 0, preorder.length - 1);if (isBST) {TreeNode root = buildTree(preorder, 0, preorder.length - 1);findLeaves(root);System.out.println("1 " + leftLeaf + " " + rightLeaf);} else {System.out.println("0 0 0");}}private static boolean verifyBST(int[] preorder, int start, int end) {if (start > end) {return true;}int rootVal = preorder[start];int mid = end + 1;for (int i = start + 1; i <= end; i++) {if (preorder[i] > rootVal) {mid = i;break;}}for (int i = mid; i <= end; i++) {if (preorder[i] <= rootVal) {return false;}}boolean leftValid = verifyBST(preorder, start + 1, mid - 1);boolean rightValid = verifyBST(preorder, mid, end);return leftValid && rightValid;}private static TreeNode buildTree(int[] preorder, int start, int end) {if (start > end) {return null;}int rootVal = preorder[start];TreeNode root = new TreeNode(rootVal);if (start == end) {return root;}int mid = end + 1;for (int i = start + 1; i <= end; i++) {if (preorder[i] > rootVal) {mid = i;break;}}root.left = buildTree(preorder, start + 1, mid - 1);root.right = buildTree(preorder, mid, end);return root;}private static void findLeaves(TreeNode root) {if (root == null) {return;}if (root.left == null && root.right == null) {if (leftLeaf == 0) {leftLeaf = root.val;}rightLeaf = root.val;}findLeaves(root.left);findLeaves(root.right);}static class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int val) {this.val = val;}}
}

代码详解

  1. 主函数

    • 读取输入并转换为整型数组。
    • 调用verifyBST验证数组是否为BST前序遍历。
    • 验证通过后构建树,查找叶子节点并输出结果。
  2. verifyBST函数

    • 递归检查数组区间是否符合BST结构。确定右子树起点,验证右子树所有元素大于根,递归检查左右子树。
  3. buildTree函数

    • 递归构建树结构,确定左右子树区间并构建节点。
  4. findLeaves函数

    • 前序遍历树,记录第一个和最后一个叶子节点值。

示例测试

示例1
输入:8 3 1 6 4 7 10 14 13
输出:1 1 13
说明:验证通过,最左叶子为1,最右为13。

示例2
输入:5 3 2 4 6 7
输出:1 2 7
说明:验证通过,最左叶子为2,最右为7。

示例3
输入:5 3 6 2
输出:0 0 0
说明:右子树中出现2,验证失败。

综合分析

该方案通过递归高效地验证前序遍历的正确性,并在验证过程中确定树的结构。虽然时间复杂度为O(n²),但对于题目约束(n≤1000)足够高效。构建树后,通过前序遍历快速找到叶子节点,确保了正确性和简洁性。递归深度可能引起栈溢出,但在合理约束下表现良好。


python

问题分析

题目要求判断给定的正整数数组是否为二叉搜索树(BST)的前序遍历结果,并输出相应的结果。如果是BST,还需要找出最左和最右的叶子节点值(伞坠信息)。主要挑战在于如何高效验证前序遍历的正确性,并在验证的同时构建树结构以确定叶子节点。

解题思路

  1. 验证BST前序遍历

    • 递归检查数组是否符合BST前序遍历的结构。根节点后,找到第一个大于根的元素作为右子树的起点,确保右子树所有元素均大于根,左子树所有元素均小于根。
  2. 构建树结构

    • 如果验证通过,递归构建二叉树,以便后续查找叶子节点。
  3. 查找叶子节点

    • 左伞坠是左子树的最左叶子节点,右伞坠是右子树的最右叶子节点。若左/右子树不存在,则对应伞坠为0。

代码实现

class TreeNode:def __init__(self, val):self.val = valself.left = Noneself.right = Nonedef verify_bst(preorder, start, end):if start > end:return Trueroot_val = preorder[start]mid = end + 1for i in range(start + 1, end + 1):if preorder[i] > root_val:mid = ibreakfor i in range(mid, end + 1):if preorder[i] <= root_val:return Falseleft_valid = verify_bst(preorder, start + 1, mid - 1)right_valid = verify_bst(preorder, mid, end)return left_valid and right_validdef build_tree(preorder, start, end):if start > end:return Noneroot_val = preorder[start]root = TreeNode(root_val)if start == end:return rootmid = end + 1for i in range(start + 1, end + 1):if preorder[i] > root_val:mid = ibreakroot.left = build_tree(preorder, start + 1, mid - 1)root.right = build_tree(preorder, mid, end)return rootdef get_left_most(node):if not node:return 0current = nodewhile current.left or current.right:if current.left:current = current.leftelse:current = current.rightreturn current.valdef get_right_most(node):if not node:return 0current = nodewhile current.right or current.left:if current.right:current = current.rightelse:current = current.leftreturn current.val# 主程序
preorder = list(map(int, input().split()))
is_bst = verify_bst(preorder, 0, len(preorder) - 1)if is_bst:root = build_tree(preorder, 0, len(preorder) - 1)left_leaf = get_left_most(root.left) if root.left else 0right_leaf = get_right_most(root.right) if root.right else 0print(f"1 {left_leaf} {right_leaf}")
else:print("0 0 0")

代码详解

  1. TreeNode类

    • 定义树的节点结构,包含值和左右子节点。
  2. verify_bst函数

    • 递归检查数组是否为BST前序遍历。确定右子树起点,验证右子树所有元素大于根,递归检查左右子树。
  3. build_tree函数

    • 递归构建树结构,确定左右子树区间并构建节点。
  4. get_left_most和get_right_most函数

    • 分别找到左子树的最左叶子节点和右子树的最右叶子节点。若子树不存在,返回0。
  5. 主程序

    • 读取输入并验证,构建树后获取左右伞坠信息。

示例测试

示例1
输入:8 3 1 6 4 7 10 14 13
输出:1 1 13
说明:验证通过,左伞坠为1,右伞坠为13。

示例2
输入:5
输出:1 0 0
说明:验证通过,但无左右子树,伞坠为0。

示例3
输入:5 6 7
输出:1 0 7
说明:验证通过,左伞坠为0,右伞坠为7。

综合分析

该方案通过递归高效验证前序遍历的正确性,并在验证过程中确定树的结构。时间复杂度为O(n²),适用于题目约束(n≤1000)。构建树后,通过特定路径查找最左和最右叶子节点,确保了正确性。处理了多种边界情况,如无左右子树或仅有一个节点的情况,确保输出符合题目要求。


JavaScript

问题分析

题目要求判断给定的正整数数组是否为二叉搜索树(BST)的前序遍历结果,并输出相应的结果。如果是BST,还需要找出最左和最右的叶子节点值(伞坠信息)。主要挑战在于如何高效验证前序遍历的正确性,并在验证的同时构建树结构以确定叶子节点。


解题思路

  1. 验证BST前序遍历

    • 递归检查数组是否符合BST前序遍历的结构。根节点后,找到第一个大于根的元素作为右子树的起点,确保右子树所有元素均大于根,左子树所有元素均小于根。
  2. 构建树结构

    • 如果验证通过,递归构建二叉树,以便后续查找叶子节点。
  3. 查找叶子节点

    • 左伞坠是左子树的最左叶子节点,右伞坠是右子树的最右叶子节点。若左/右子树不存在,则对应伞坠为0。

代码实现

class TreeNode {constructor(val) {this.val = val;this.left = null;this.right = null;}
}function verifyBST(preorder, start, end) {if (start > end) return true;const rootVal = preorder[start];let mid = end + 1; // 初始化为 end+1,表示右子树不存在// 找到第一个大于根的元素,作为右子树的起点for (let i = start + 1; i <= end; i++) {if (preorder[i] > rootVal) {mid = i;break;}}// 检查右子树是否全大于根for (let i = mid; i <= end; i++) {if (preorder[i] <= rootVal) {return false;}}// 递归验证左子树和右子树const leftValid = verifyBST(preorder, start + 1, mid - 1);const rightValid = verifyBST(preorder, mid, end);return leftValid && rightValid;
}function buildTree(preorder, start, end) {if (start > end) return null;const rootVal = preorder[start];const root = new TreeNode(rootVal);if (start === end) return root; // 叶子节点let mid = end + 1;// 找到右子树的起点for (let i = start + 1; i <= end; i++) {if (preorder[i] > rootVal) {mid = i;break;}}root.left = buildTree(preorder, start + 1, mid - 1);root.right = buildTree(preorder, mid, end);return root;
}function getLeftLeaf(node) {if (!node) return 0;let current = node;// 不断向左或向右寻找最左叶子while (current.left || current.right) {if (current.left) {current = current.left;} else {current = current.right;}}return current.val;
}function getRightLeaf(node) {if (!node) return 0;let current = node;// 不断向右或向左寻找最右叶子while (current.right || current.left) {if (current.right) {current = current.right;} else {current = current.left;}}return current.val;
}// 主程序
const input = require('fs').readFileSync(0, 'utf-8').trim().split(/\s+/);
const preorder = input.map(Number);if (verifyBST(preorder, 0, preorder.length - 1)) {const root = buildTree(preorder, 0, preorder.length - 1);const left = root.left ? getLeftLeaf(root.left) : 0;const right = root.right ? getRightLeaf(root.right) : 0;console.log(`1 ${left} ${right}`);
} else {console.log('0 0 0');
}

代码详解

  1. TreeNode类

    • 定义树的节点结构,包含值和左右子节点。
  2. verifyBST函数

    • 第1行:若当前区间无效(start > end),直接返回 true
    • 第3-8行:找到第一个大于根节点的元素,作为右子树的起点。
    • 第10-13行:检查右子树所有元素是否均大于根。
    • 第15-17行:递归验证左子树和右子树。
  3. buildTree函数

    • 第1-2行:若区间无效,返回 null
    • 第4-5行:创建根节点,若区间长度为1(叶子节点),直接返回。
    • 第7-12行:找到右子树起点,递归构建左右子树。
  4. getLeftLeaf和getRightLeaf函数

    • 核心逻辑:沿着左(或右)路径向下,直到找到叶子节点。
    • 循环条件:只要当前节点有子节点,继续遍历。
    • 返回值:最终找到的叶子节点的值。
  5. 主程序

    • 输入处理:从标准输入读取数据,并转换为数字数组。
    • 验证与构建树:若验证通过,构建树并查找叶子节点。
    • 输出结果:根据验证结果输出对应信息。

示例测试

  1. 输入示例1

    8 3 1 6 4 7 10 14 13
    

    输出

    1 1 13
    

    解释

    • 数组是BST的前序遍历。
    • 最左叶子节点是 1,最右叶子节点是 13
  2. 输入示例2

    5
    

    输出

    1 0 0
    

    解释

    • 单节点树,无左右子树,伞坠均为0。
  3. 输入示例3

    5 3 6 2
    

    输出

    0 0 0
    

    解释

    • 右子树中存在 2(小于根节点 5),验证失败。

综合分析

  1. 时间复杂度

    • 验证函数:递归分割数组,最坏时间复杂度为 (O(n^2)),但实际表现较好。
    • 构建树与查找叶子:复杂度为 (O(n)),总体复杂度由验证函数主导。
  2. 空间复杂度

    • 递归栈深度为树的高度,最坏为 (O(n))(退化成链表)。
  3. 优势

    • 递归逻辑清晰,直接体现BST前序遍历的性质。
    • 叶子查找通过路径遍历,无需全局变量或复杂遍历。
  4. 适用场景

    • 输入规模较小(题目约束数组长度最多1000),递归深度可控。
    • 逻辑简洁,适合快速验证问题。

C++

问题分析

题目要求判断一个数组是否为二叉搜索树(BST)的前序遍历结果,并输出左右伞坠(最左和最右叶子节点值)。若数组非BST前序,输出0。核心挑战在于验证前序的有效性及高效构建树结构。


解题思路

  1. 验证前序合法性

    • 递归分割:根节点后,找到第一个大于根的元素作为右子树起点,确保右子树所有元素大于根,左子树元素均小于根。
    • 递归验证:对左右子树递归执行相同操作。
  2. 构建二叉树

    • 递归构建,确定左右子树区间,生成树节点。
  3. 查找伞坠

    • 左伞坠:左子树的最左叶子(优先左子,若无则向右)。
    • 右伞坠:右子树的最右叶子(优先右子,若无则向左)。

代码实现

#include <iostream>
#include <vector>
#include <sstream>
#include <string>using namespace std;struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};class Solution {
public:bool verifyBST(vector<int>& preorder, int start, int end) {if (start > end) return true;int rootVal = preorder[start];int mid = end + 1; // 右子树的起始位置(默认无右子树)// 找到第一个大于根的元素作为右子树起点for (int i = start + 1; i <= end; ++i) {if (preorder[i] > rootVal) {mid = i;break;}}// 检查右子树是否全大于根for (int i = mid; i <= end; ++i) {if (preorder[i] <= rootVal) return false;}// 递归验证左右子树return verifyBST(preorder, start + 1, mid - 1) && verifyBST(preorder, mid, end);}TreeNode* buildTree(vector<int>& preorder, int start, int end) {if (start > end) return nullptr;TreeNode* root = new TreeNode(preorder[start]);if (start == end) return root; // 叶子节点int mid = end + 1;for (int i = start + 1; i <= end; ++i) {if (preorder[i] > root->val) {mid = i;break;}}root->left = buildTree(preorder, start + 1, mid - 1);root->right = buildTree(preorder, mid, end);return root;}int getLeftLeaf(TreeNode* node) {if (!node) return 0;TreeNode* cur = node;while (cur->left || cur->right) {if (cur->left) cur = cur->left;else cur = cur->right;}return cur->val;}int getRightLeaf(TreeNode* node) {if (!node) return 0;TreeNode* cur = node;while (cur->right || cur->left) {if (cur->right) cur = cur->right;else cur = cur->left;}return cur->val;}
};int main() {string line;getline(cin, line);istringstream iss(line);vector<int> preorder;int num;while (iss >> num) preorder.push_back(num);Solution sol;bool isBST = sol.verifyBST(preorder, 0, preorder.size() - 1);if (isBST) {TreeNode* root = sol.buildTree(preorder, 0, preorder.size() - 1);int left = root->left ? sol.getLeftLeaf(root->left) : 0;int right = root->right ? sol.getRightLeaf(root->right) : 0;cout << "1 " << left << " " << right << endl;} else {cout << "0 0 0" << endl;}return 0;
}

代码详解

  1. TreeNode结构体

    • 定义树节点,包含值、左右子节点指针。
  2. verifyBST函数

    • 终止条件:区间无效时返回 true
    • 确定右子树起点:遍历找到第一个大于根的元素。
    • 检查右子树合法性:确保右子树元素均大于根。
    • 递归验证:分别验证左右子树是否为合法BST前序。
  3. buildTree函数

    • 递归构建树节点,划分左右子树区间,生成子树。
  4. getLeftLeaf/getRightLeaf函数

    • 通过循环找到最左/右叶子节点,优先沿左/右路径,若无则转向。
  5. 主函数

    • 读取输入并解析为整数数组。
    • 验证是否为BST前序,构建树并查找伞坠,输出结果。

示例测试

示例1
输入:

8 3 1 6 4 7 10 14 13

输出:

1 1 13

解析

  • 数组是BST前序,左伞坠在左子树最左叶子(1),右伞坠在右子树最右叶子(13)。

示例2
输入:

5

输出:

1 0 0

解析

  • 单节点树,无左右子树,伞坠均为0。

示例3
输入:

5 6 7

输出:

1 0 7

解析

  • 右子树存在,右伞坠是7,左子树不存在,左伞坠为0。

综合分析

  1. 时间复杂度

    • 验证函数:最坏情况下(如链表结构)时间复杂度为 (O(n^2))。
    • 构建树和查找叶子:时间复杂度 (O(n)),总体复杂度由验证主导。
  2. 空间复杂度

    • 递归调用栈深度为树的高度,最坏情况(链表)为 (O(n))。
  3. 优势

    • 直接利用BST前序特性递归验证,逻辑清晰。
    • 避免全局变量,通过函数参数传递状态,结构简洁。
  4. 适用场景

    • 处理规模较小(数组长度≤1000)时效率可接受。
    • 递归实现直观,适合快速验证和树构建。

C

问题分析

题目要求判断一个数组是否为二叉搜索树(BST)的前序遍历结果,并输出左右伞坠(最左和最右叶子节点值)。若数组非BST前序,输出0。核心挑战在于验证前序的有效性及高效构建树结构。


解题思路

  1. 验证前序合法性

    • 递归分割:根节点后,找到第一个大于根的元素作为右子树起点,确保右子树所有元素大于根,左子树元素均小于根。
    • 递归验证:对左右子树递归执行相同操作。
  2. 构建二叉树

    • 递归构建,确定左右子树区间,生成树节点。
  3. 查找伞坠

    • 左伞坠:左子树的最左叶子(优先左子,若无则向右)。
    • 右伞坠:右子树的最右叶子(优先右子,若无则向左)。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>// 树节点结构体
typedef struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
} TreeNode;// 验证前序合法性
bool verifyBST(int *preorder, int start, int end) {if (start > end) return true;int rootVal = preorder[start];int mid = end + 1; // 右子树起点(默认无右子树)// 找到第一个大于根的元素for (int i = start + 1; i <= end; i++) {if (preorder[i] > rootVal) {mid = i;break;}}// 检查右子树是否全大于根for (int i = mid; i <= end; i++) {if (preorder[i] <= rootVal) return false;}// 递归验证左右子树return verifyBST(preorder, start + 1, mid - 1) &&verifyBST(preorder, mid, end);
}// 构建二叉树
TreeNode *buildTree(int *preorder, int start, int end) {if (start > end) return NULL;TreeNode *root = (TreeNode *)malloc(sizeof(TreeNode));root->val = preorder[start];root->left = root->right = NULL;if (start == end) return root; // 叶子节点int mid = end + 1;for (int i = start + 1; i <= end; i++) {if (preorder[i] > root->val) {mid = i;break;}}root->left = buildTree(preorder, start + 1, mid - 1);root->right = buildTree(preorder, mid, end);return root;
}// 找左伞坠
int getLeftLeaf(TreeNode *node) {if (!node) return 0;TreeNode *cur = node;while (cur->left || cur->right) {if (cur->left) cur = cur->left;else cur = cur->right;}return cur->val;
}// 找右伞坠
int getRightLeaf(TreeNode *node) {if (!node) return 0;TreeNode *cur = node;while (cur->right || cur->left) {if (cur->right) cur = cur->right;else cur = cur->left;}return cur->val;
}// 输入处理:将字符串转换为数组
void parseInput(char *input, int **preorder, int *size) {int capacity = 10;*preorder = (int *)malloc(capacity * sizeof(int));*size = 0;char *token = strtok(input, " ");while (token) {if (*size >= capacity) {capacity *= 2;*preorder = realloc(*preorder, capacity * sizeof(int));}(*preorder)[(*size)++] = atoi(token);token = strtok(NULL, " ");}
}int main() {char input[10000];fgets(input, sizeof(input), stdin);int *preorder = NULL;int size = 0;parseInput(input, &preorder, &size);if (verifyBST(preorder, 0, size - 1)) {TreeNode *root = buildTree(preorder, 0, size - 1);int left = root->left ? getLeftLeaf(root->left) : 0;int right = root->right ? getRightLeaf(root->right) : 0;printf("1 %d %d\n", left, right);} else {printf("0 0 0\n");}free(preorder);return 0;
}

代码详解

  1. 树节点结构体

    • TreeNode包含值val和左右子节点指针,用于表示二叉树。
  2. verifyBST函数

    • 终止条件:当区间无效时(start > end)返回true
    • 查找右子树起点:遍历找到第一个大于根节点的元素位置mid
    • 检查右子树合法性:确保右子树所有元素均大于根。
    • 递归验证:对左右子树递归调用verifyBST
  3. buildTree函数

    • 递归构建二叉树,根据mid划分左右子树区间。
    • 为每个节点分配内存,并初始化左右指针为NULL
  4. getLeftLeaf/getRightLeaf函数

    • 通过循环找到最左/右叶子节点。优先沿左/右路径向下,若无则转向另一侧。
  5. parseInput函数

    • 将输入的字符串按空格分割为整数数组,动态扩展数组容量。
  6. 主函数

    • 读取输入并解析为数组。
    • 验证是否为BST前序,构建树并查找伞坠。
    • 输出结果并释放动态分配的内存。

示例测试

示例1
输入:

8 3 1 6 4 7 10 14 13

输出:

1 1 13

解析

  • 数组是BST前序,左伞坠是左子树的最左叶子(1),右伞坠是右子树的最右叶子(13)。

示例2
输入:

5

输出:

1 0 0

解析

  • 单节点树,无左右子树,伞坠均为0。

示例3
输入:

5 3 6 2

输出:

0 0 0

解析

  • 右子树中存在2(小于根节点5),验证失败。

综合分析

  1. 时间复杂度

    • 验证函数:最坏时间复杂度为 (O(n^2))(如链表结构),但实际场景下表现良好。
    • 构建树和查找叶子:时间复杂度为 (O(n)),总体复杂度由验证主导。
  2. 空间复杂度

    • 递归调用栈深度为树的高度,最坏情况(链表结构)为 (O(n))。
    • 动态数组和树节点的空间复杂度为 (O(n))。
  3. 优势

    • 直接利用BST前序特性递归验证,逻辑清晰。
    • 动态数组处理输入,适应不同规模的输入数据。
  4. 适用场景

    • 处理数组长度≤1000时效率可接受。
    • 递归实现直观,适合快速验证和树构建。

GO

问题分析

题目要求判断一个数组是否为二叉搜索树(BST)的前序遍历结果,并输出左右伞坠(最左和最右叶子节点值)。若数组非BST前序,输出0。核心挑战在于验证前序的有效性及高效构建树结构。


解题思路

  1. 验证前序合法性

    • 递归分割:根节点后,找到第一个大于根的元素作为右子树起点,确保右子树所有元素大于根,左子树元素均小于根。
    • 递归验证:对左右子树递归执行相同操作。
  2. 构建二叉树

    • 递归构建,确定左右子树区间,生成树节点。
  3. 查找伞坠

    • 左伞坠:左子树的最左叶子(优先左子,若无则向右)。
    • 右伞坠:右子树的最右叶子(优先右子,若无则向左)。

代码实现

package mainimport ("bufio""fmt""os""strconv""strings"
)type TreeNode struct {Val   intLeft  *TreeNodeRight *TreeNode
}// 验证前序遍历是否合法
func verifyBST(preorder []int, start, end int) bool {if start > end {return true}rootVal := preorder[start]mid := end + 1 // 右子树起点(默认无右子树)// 找到第一个大于根的元素for i := start + 1; i <= end; i++ {if preorder[i] > rootVal {mid = ibreak}}// 检查右子树是否全部大于根for i := mid; i <= end; i++ {if preorder[i] <= rootVal {return false}}// 递归验证左右子树return verifyBST(preorder, start+1, mid-1) && verifyBST(preorder, mid, end)
}// 构建二叉树
func buildTree(preorder []int, start, end int) *TreeNode {if start > end {return nil}root := &TreeNode{Val: preorder[start]}if start == end { // 叶子节点直接返回return root}mid := end + 1for i := start + 1; i <= end; i++ {if preorder[i] > root.Val {mid = ibreak}}root.Left = buildTree(preorder, start+1, mid-1)root.Right = buildTree(preorder, mid, end)return root
}// 获取左伞坠(最左叶子节点)
func getLeftLeaf(node *TreeNode) int {if node == nil {return 0}cur := nodefor cur.Left != nil || cur.Right != nil {if cur.Left != nil {cur = cur.Left} else {cur = cur.Right}}return cur.Val
}// 获取右伞坠(最右叶子节点)
func getRightLeaf(node *TreeNode) int {if node == nil {return 0}cur := nodefor cur.Right != nil || cur.Left != nil {if cur.Right != nil {cur = cur.Right} else {cur = cur.Left}}return cur.Val
}// 主函数
func main() {scanner := bufio.NewScanner(os.Stdin)scanner.Scan()input := scanner.Text()strs := strings.Fields(input)preorder := make([]int, len(strs))for i, s := range strs {num, _ := strconv.Atoi(s)preorder[i] = num}if verifyBST(preorder, 0, len(preorder)-1) {root := buildTree(preorder, 0, len(preorder)-1)left := 0if root.Left != nil {left = getLeftLeaf(root.Left)}right := 0if root.Right != nil {right = getRightLeaf(root.Right)}fmt.Printf("1 %d %d\n", left, right)} else {fmt.Println("0 0 0")}
}

代码详解

  1. 树节点定义

    • TreeNode结构体包含值Val和左右子节点指针,用于表示二叉树。
  2. verifyBST函数

    • 终止条件:当区间无效时(start > end)返回true
    • 查找右子树起点:遍历找到第一个大于根节点的元素位置mid
    • 检查右子树合法性:确保右子树所有元素均大于根。
    • 递归验证:对左右子树递归调用verifyBST
  3. buildTree函数

    • 递归构建二叉树,根据mid划分左右子树区间。
    • 为每个节点分配内存,并初始化左右指针为nil
  4. getLeftLeaf/getRightLeaf函数

    • 通过循环找到最左/右叶子节点。优先沿左/右路径向下,若无则转向另一侧。
  5. 主函数

    • 读取输入并解析为整数数组。
    • 验证是否为BST前序,构建树并查找伞坠。
    • 输出结果。

示例测试

示例1
输入:

8 3 1 6 4 7 10 14 13

输出:

1 1 13

解析

  • 数组是BST前序,左伞坠是左子树的最左叶子(1),右伞坠是右子树的最右叶子(13)。

示例2
输入:

5

输出:

1 0 0

解析

  • 单节点树,无左右子树,伞坠均为0。

示例3
输入:

5 3 6 2

输出:

0 0 0

解析

  • 右子树中存在2(小于根节点5),验证失败。

综合分析

  1. 时间复杂度

    • 验证函数:最坏时间复杂度为 (O(n^2))(如链表结构),但实际场景下表现良好。
    • 构建树和查找叶子:时间复杂度为 (O(n)),总体复杂度由验证主导。
  2. 空间复杂度

    • 递归调用栈深度为树的高度,最坏情况(链表结构)为 (O(n))。
  3. 优势

    • 利用Go的简洁语法和自动内存管理,代码更易维护。
    • 输入处理直接使用标准库函数,避免手动解析的复杂性。
  4. 适用场景

    • 处理数组长度≤1000时效率可接受。
    • 递归实现直观,适合快速验证和树构建。

更多内容:

https://www.kdocs.cn/l/cvk0eoGYucWA

本文发表于【纪元A梦】,关注我,获取更多实用教程/资源!

相关文章:

  • 在WSL2+Ubuntu22.04中通过conda pack导出一个conda环境包,然后尝试导入该环境包
  • 【Linux网络】打造初级网络计算器 - 从协议设计到服务实现
  • 1.4 大模型应用产品与技术架构
  • 静态多态和动态多态的区别
  • 【Tauri】桌面程序exe开发 - Tauri+Vue开发Windows应用 - 比Electron更轻量!8MB!
  • 【高频考点精讲】实现垂直居中的多种CSS方法比较与最佳实践
  • BS架构与CS架构的对比分析:了解两种架构的不同特点与应用
  • 计算机网络 | 应用层(4)--DNS:因特网的目录服务
  • (done) 吴恩达版提示词工程 5. 推理 (情绪分类,控制输出格式,输出 JSON,集成多个任务,文本主题推断和索引,主题内容提醒)
  • 来自 Bisheng 关于微调的内容总结
  • [mysql]约束(上)
  • 19.【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--当前项目拆分规划
  • 前端开发中列表无限加载功能的实现与优化
  • 神经网络与深度学习第四章-前馈神经网络
  • C++ 同步原语
  • 【股票系统】使用docker本地构建ai-hedge-fund项目,模拟大师炒股进行分析。人工智能的对冲基金的开源项目
  • 下垂控制属于构网型控制技术
  • 药监平台上传数据报资源码不存在
  • 焕新升级001,50M/S告别限速!
  • leetcode66.加一
  • 俄罗斯称已收复库尔斯克州,普京发表讲话
  • 应勇:以法治力量服务黄河流域生态保护和高质量发展
  • 甘肃张掖至重庆航线开通,串起西北与西南文旅“黄金走廊”
  • 中青报:“猿辅导员工猝死”事件上热搜,是对健康职场环境的共同关切
  • 珠海市香洲区原区长刘齐英落马,此前已被终止省人大代表资格
  • 受折纸艺术启发可移动可变形的新型超材料问世