华为OD机试真题——阿里巴巴找黄金宝箱Ⅰ(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型

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

华为OD机试真题《阿里巴巴找黄金宝箱Ⅰ》:


文章快捷目录

题目描述及说明

Java

python

JavaScript

C

GO

更多内容


题目名称:阿里巴巴找黄金宝箱Ⅰ


  1. 知识点:前缀和、双指针(或逻辑模拟)
  2. 时间限制:1秒
  3. 空间限制:256MB
  4. 限定语言:不限

题目描述

一贫如洗的樵夫阿里巴巴在去砍柴的路上,无意中发现了强盗集团的藏宝地,藏宝地有编号从0~N的箱子,每个箱子上面贴有一个数字,箱子中可能有一个黄金宝箱。
黄金宝箱满足:排在它之前的所有箱子数字和等于排在它之后的所有箱子数字和;

  • 第一个箱子左边部分的数字和定义为0;
  • 最后一个宝箱右边部分的数字和定义为0。
    请帮阿里巴巴找到黄金宝箱,输出第一个满足条件的黄金宝箱编号,如果不存在黄金宝箱,请返回-1。

输入描述

箱子上贴的数字列表,使用逗号分隔,例如:1,-1,0

  • 宝箱的数量不小于1个,不超过10000;
  • 宝箱上贴的数值范围不低于-1000,不超过1000。

输出描述

第一个黄金宝箱的编号(从0开始计数)。

示例

  1. 输入:2,5,-1,8,6,输出:3
    • 下标3之前的数字和为:2 + 5 + -1 = 6,之后的数字和为:6 = 6
  2. 输入:8,9,输出:-1(无满足条件的位置)。
  3. 输入:11,输出:0(下标0左右和均为0)。

Java

问题分析

我们需要找到数组中第一个满足左边元素和等于右边元素和的索引位置。左边和右边的定义分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。

解题思路

  1. 总和计算:首先计算数组所有元素的总和。
  2. 遍历检查 :遍历数组,维护一个累积的左边和 leftSum。对于每个位置 i,右边的和为 totalSum - leftSum - nums[i]。如果左边和等于右边的和,则返回当前索引。
  3. 线性时间复杂度:该方法只需两次遍历数组(一次计算总和,一次查找位置),时间复杂度为 O(n),空间复杂度为 O(1)(不考虑输入存储空间)。

代码实现

java 复制代码
public class Main {
    public static void main(String[] args) {
        // 读取输入并转换为整数数组
        java.util.Scanner scanner = new java.util.Scanner(System.in);
        String input = scanner.nextLine();
        String[] parts = input.split(",");
        int[] nums = new int[parts.length];
        for (int i = 0; i < parts.length; i++) {
            nums[i] = Integer.parseInt(parts[i]);
        }
        
        // 计算总和
        int totalSum = 0;
        for (int num : nums) {
            totalSum += num;
        }
        
        // 遍历数组查找黄金宝箱位置
        int leftSum = 0;
        for (int i = 0; i < nums.length; i++) {
            int current = nums[i];
            // 右边的和 = 总和 - 左边和 - 当前元素值
            int rightSum = totalSum - leftSum - current;
            if (leftSum == rightSum) {
                System.out.println(i);
                return;
            }
            leftSum += current;
        }
        
        // 未找到符合条件的宝箱
        System.out.println(-1);
    }
}

代码详解

  1. 输入处理

    • scanner.nextLine() 读取输入字符串。
    • split(",") 将字符串按逗号分割成字符串数组。
    • 转换为 int[] 数组 nums
  2. 总和计算

    • 遍历数组累加所有元素的值得到 totalSum
  3. 遍历检查

    • 初始化 leftSum 为0,表示当前位置左边的累积和。
    • 遍历每个元素 nums[i],计算右边的和 rightSum
    • 如果 leftSum 等于 rightSum,输出当前索引并结束程序。
    • 否则,将当前元素值加到 leftSum 中,继续下一个元素。
  4. 结果输出

    • 若遍历结束未找到符合条件的索引,输出-1。

示例测试

示例1

输入:2,5,-1,8,6

输出:3

解析:索引3左边和为2+5+(-1)=6,右边和为6,相等。

示例2

输入:8,9

输出:-1

解析:两个位置均不满足左边和等于右边和。

示例3

输入:11

输出:0

解析:左边和与右边和均为0。

综合分析

  1. 时间复杂度:两次遍历数组,时间复杂度为 O(n),n为数组长度。对于最大输入规模1e4,完全可行。
  2. 空间复杂度:除了存储输入数组外,仅使用常数空间。
  3. 最优性:该方法无法进一步优化时间复杂度,因为必须遍历所有元素才能确定结果。空间复杂度已是最优。
  4. 适用性:适用于所有合法输入,处理边界条件(如单个元素)正确。

python

问题分析

我们需要找到数组中第一个满足左边元素和等于右边元素和的索引位置。左边和右边的定义分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。


解题思路

  1. 总和计算 :首先计算数组所有元素的总和 total_sum
  2. 遍历检查 :遍历数组,维护一个累积的左边和 left_sum。对于每个位置 i,右边的和为 total_sum - left_sum - nums[i]。如果左边和等于右边的和,则返回当前索引。
  3. 线性时间复杂度:该方法只需两次遍历数组(一次计算总和,一次查找位置),时间复杂度为 O(n),空间复杂度为 O(1)。

代码实现

python 复制代码
# 读取输入并转换为整数列表
nums = list(map(int, input().strip().split(',')))

# 计算数组所有元素的总和
total_sum = sum(nums)

# 初始化左边和为0
left_sum = 0

# 遍历数组的每个元素
for i in range(len(nums)):
    current = nums[i]
    # 计算右边的和:总和 - 左边和 - 当前元素
    right_sum = total_sum - left_sum - current
    # 判断左边和是否等于右边的和
    if left_sum == right_sum:
        print(i)
        exit()  # 找到第一个满足条件的位置后立即退出
    # 将当前元素值累加到左边和中,供下一个元素使用
    left_sum += current

# 若遍历完所有元素仍未找到,输出-1
print(-1)

代码详解

  1. 输入处理

    • input().strip() 读取输入并去除首尾空格。
    • split(',') 将字符串按逗号分割成多个子字符串。
    • map(int, ...) 将每个子字符串转换为整数,最终生成整数列表 nums
  2. 总和计算

    • sum(nums) 快速计算数组的总和 total_sum
  3. 遍历检查

    • left_sum 初始化为0,表示当前元素左边的累积和。
    • 遍历每个元素 nums[i]
      • right_sum = total_sum - left_sum - current:右边的和为总和减去左边和和当前元素值。
      • 如果 left_sum == right_sum,直接输出当前索引并终止程序。
      • 否则将当前元素值累加到 left_sum,继续处理下一个元素。
  4. 结果输出

    • 若遍历结束未找到符合条件的索引,输出-1。

示例测试

示例1

输入:

复制代码
2,5,-1,8,6

输出:

复制代码
3

解析:

  • 总和为 2+5+(-1)+8+6=20
  • 遍历到索引3(元素8)时:
    • left_sum = 2+5+(-1) = 6
    • right_sum = 20 - 6 - 8 = 6,左右相等,输出3。

示例2

输入:

复制代码
8,9

输出:

复制代码
-1

解析:

  • 总和为17。
  • 索引0:left_sum=0right_sum=17-0-8=9(0≠9)。
  • 索引1:left_sum=8right_sum=17-8-9=0(8≠0),无解。

示例3

输入:

复制代码
11

输出:

复制代码
0

解析:

  • 总和为11。
  • 索引0:left_sum=0right_sum=11-0-11=0,满足条件。

综合分析

  1. 时间复杂度

    • 计算总和:一次遍历,O(n)。
    • 遍历检查:一次遍历,O(n)。
    • 总体复杂度:O(n),完全适合题目中的最大输入规模(1e4)。
  2. 空间复杂度

    • 仅需存储输入数组和几个临时变量,空间复杂度为 O(1)。
  3. 最优性

    • 这是最优解法,因为必须遍历所有元素才能确保找到第一个符合条件的索引,无法进一步优化时间复杂度。
  4. 适用场景

    • 处理单个或多个元素的场景均正确,能高效处理边界条件(如数组仅一个元素)。

JavaScript

问题分析

我们需要找到数组中第一个满足左边元素和等于右边元素和的索引位置。左边和右边的定义分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。


解题思路

  1. 总和计算 :首先计算数组所有元素的总和 totalSum
  2. 遍历检查 :遍历数组,维护一个累积的左边和 leftSum。对于每个位置 i,右边的和为 totalSum - leftSum - nums[i]。如果左边和等于右边的和,则返回当前索引。
  3. 线性时间复杂度:该方法只需两次遍历数组(一次计算总和,一次查找位置),时间复杂度为 O(n),空间复杂度为 O(1)。

代码实现

javascript 复制代码
const readline = require('readline');

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

rl.question('', (input) => {
    // 处理输入:分割字符串为数字数组
    const nums = input.split(',').map(Number);
    
    // 计算总和
    const totalSum = nums.reduce((acc, curr) => acc + curr, 0);
    
    let leftSum = 0; // 初始化左边和为0
    
    // 遍历数组每个元素
    for (let i = 0; i < nums.length; i++) {
        const current = nums[i];
        // 右边的和 = 总和 - 左边和 - 当前元素值
        const rightSum = totalSum - leftSum - current;
        
        // 找到符合条件的第一个位置
        if (leftSum === rightSum) {
            console.log(i);
            rl.close();
            return;
        }
        
        // 将当前元素累加到左边和中
        leftSum += current;
    }
    
    // 遍历完未找到,输出-1
    console.log(-1);
    rl.close();
});

代码详解

  1. 输入处理

    • input.split(',') 将输入的字符串按逗号分割成字符串数组。
    • map(Number) 将每个字符串转换为数字,生成数字数组 nums
  2. 总和计算

    • reduce((acc, curr) => acc + curr, 0) 遍历数组累加所有元素的值,得到总和 totalSum
  3. 遍历检查

    • 初始化 leftSum 为0,表示当前元素左边的累积和。
    • 遍历每个元素 nums[i]
      • rightSum = totalSum - leftSum - current:右边的和为总和减去左边和和当前元素值。
      • 如果 leftSum === rightSum,直接输出当前索引并结束程序。
      • 否则将当前元素值累加到 leftSum,继续处理下一个元素。
  4. 结果输出

    • 若遍历结束未找到符合条件的索引,输出-1。

示例测试

示例1

输入:

复制代码
2,5,-1,8,6

输出:

复制代码
3

解析:

  • 总和为 2+5+(-1)+8+6=20
  • 遍历到索引3(元素8)时:
    • leftSum = 2+5+(-1) = 6
    • rightSum = 20 -6 -8 = 6,左右相等,输出3。

示例2

输入:

复制代码
8,9

输出:

复制代码
-1

解析:

  • 总和为17。
  • 索引0:leftSum=0rightSum=17-0-8=9(0≠9)。
  • 索引1:leftSum=8rightSum=17-8-9=0(8≠0),无解。

示例3

输入:

复制代码
11

输出:

复制代码
0

解析:

  • 总和为11。
  • 索引0:leftSum=0rightSum=11-0-11=0,满足条件。

综合分析

  1. 时间复杂度

    • 计算总和:一次遍历,O(n)。
    • 遍历检查:一次遍历,O(n)。
    • 总体复杂度:O(n),完全适合题目中的最大输入规模(1e4)。
  2. 空间复杂度

    • 仅需存储输入数组和几个临时变量,空间复杂度为 O(1)。
  3. 最优性

    • 这是最优解法,因为必须遍历所有元素才能确保找到第一个符合条件的索引,无法进一步优化时间复杂度。
  4. 适用场景

    • 处理单个或多个元素的场景均正确,能高效处理边界条件(如数组仅一个元素)。

C++

问题分析

我们需要在整数数组中找到第一个满足左边元素和等于右边元素和的索引。左边和右边的和分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。


解题思路

  1. 输入处理:将输入的逗号分隔字符串转换为整数数组。
  2. 总和计算:遍历数组计算所有元素的总和。
  3. 遍历检查:维护左边累积和,逐个元素计算右边的和,若相等则返回索引。

代码实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <sstream>

using namespace std;

int main() {
    string input;
    getline(cin, input); // 读取输入字符串
    
    vector<int> nums;
    stringstream ss(input); // 将字符串转为流以分割
    string token;
    // 按逗号分割字符串并转为整数数组
    while (getline(ss, token, ',')) {
        nums.push_back(stoi(token));
    }
    
    int totalSum = 0;
    for (int num : nums) { // 计算总和
        totalSum += num;
    }
    
    int leftSum = 0;
    for (int i = 0; i < nums.size(); ++i) { // 遍历检查每个元素
        int current = nums[i];
        int rightSum = totalSum - leftSum - current; // 计算右边和
        if (leftSum == rightSum) { // 找到第一个符合条件的索引
            cout << i << endl;
            return 0;
        }
        leftSum += current; // 累积左边和
    }
    
    cout << -1 << endl; // 未找到
    return 0;
}

代码详解

  1. 输入处理

    • getline(cin, input):读取整行输入。
    • stringstream 分割字符串为子字符串,通过 stoi 转换为整数存入 nums
  2. 总和计算

    • 遍历数组,累加所有元素的值到 totalSum
  3. 遍历检查

    • leftSum 初始化为0,表示当前位置左边的累积和。
    • 对于每个元素 nums[i]
      • 计算右边和totalSum - leftSum - current
      • 判断条件:若左边和等于右边和,输出索引并终止程序。
      • 更新左边和 :将当前元素值累加到 leftSum

示例测试

示例1

输入:

复制代码
2,5,-1,8,6

输出:

复制代码
3

解析:

  • 总和为20,遍历到索引3时,左边和6等于右边和6。

示例2

输入:

复制代码
8,9

输出:

复制代码
-1

解析:

  • 总和为17,左右和无法相等。

示例3

输入:

复制代码
11

输出:

复制代码
0

解析:

  • 单元素数组左右和均为0,输出0。

综合分析

  1. 时间复杂度

    • 总和计算:一次遍历,O(n)。
    • 遍历检查:一次遍历,O(n)。
    • 总体复杂度:O(n),适合最大输入规模1e4。
  2. 空间复杂度

    • 存储输入数组的 O(n) 空间,其他变量为常数空间。
  3. 最优性

    • 必须遍历所有元素才能确定结果,无法进一步优化时间复杂度。
  4. 适用场景

    • 处理单个或多个元素均正确,边界条件处理得当。

C

问题分析

我们需要在整数数组中找到第一个满足左边元素和等于右边元素和的索引。左边和右边的和分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。


解题思路

  1. 输入处理:读取逗号分隔的字符串,转换为整数数组。
  2. 总和计算:遍历数组计算所有元素的总和。
  3. 遍历检查:维护左边累积和,逐个元素计算右边的和,若相等则返回索引。

代码实现

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

int main() {
    char input[100000]; // 假设输入最大长度足够
    if (fgets(input, sizeof(input), stdin) == NULL) {
        return -1; // 处理输入错误
    }

    // 去除末尾换行符
    size_t len = strlen(input);
    if (len > 0 && input[len - 1] == '\n') {
        input[len - 1] = '\0';
    }

    // 计算元素个数(逗号数量 +1)
    int count = 1;
    for (int i = 0; input[i] != '\0'; i++) {
        if (input[i] == ',') count++;
    }

    // 动态分配数组内存
    int *nums = (int *)malloc(count * sizeof(int));
    if (nums == NULL) {
        return -1; // 内存分配失败
    }

    // 分割字符串并填充数组
    char *token = strtok(input, ",");
    int index = 0;
    while (token != NULL) {
        nums[index++] = atoi(token); // 字符串转整数
        token = strtok(NULL, ",");
    }

    // 计算总和
    int totalSum = 0;
    for (int i = 0; i < count; i++) {
        totalSum += nums[i];
    }

    // 遍历检查每个位置
    int leftSum = 0;
    for (int i = 0; i < count; i++) {
        int current = nums[i];
        int rightSum = totalSum - leftSum - current; // 右边和
        if (leftSum == rightSum) {
            printf("%d\n", i);
            free(nums); // 释放内存
            return 0;   // 提前终止
        }
        leftSum += current; // 更新左边和
    }

    printf("-1\n"); // 未找到
    free(nums);     // 释放内存

    return 0;
}

代码详解

  1. 输入处理

    • fgets 读取输入到 input 缓冲区。
    • 去除末尾的换行符,确保字符串正确分割。
  2. 计算元素数量

    • 遍历字符串统计逗号数量,元素数量为逗号数+1。
  3. 动态分配数组

    • 根据计算的 count 分配足够内存存储整数数组。
  4. 分割字符串填充数组

    • strtok 按逗号分割字符串,逐个转换为整数存入数组。
  5. 总和计算

    • 遍历数组累加所有元素,得到总和 totalSum
  6. 遍历检查

    • 维护 leftSum 表示当前位置左边的累积和。
    • 对每个元素计算 rightSum,若等于 leftSum,输出索引并终止。
    • 否则更新 leftSum 并继续遍历。
  7. 内存释放

    • 使用 free 释放动态分配的数组内存,避免内存泄漏。

示例测试

示例1

输入:

复制代码
2,5,-1,8,6

输出:

复制代码
3

解析:

  • 总和为 2+5+(-1)+8+6=20
  • 遍历到索引3时,左边和 6,右边和 20-6-8=6,相等。

示例2

输入:

复制代码
8,9

输出:

复制代码
-1

解析:

  • 总和为 17,遍历后无左右和相等的位置。

示例3

输入:

复制代码
11

输出:

复制代码
0

解析:

  • 单元素数组,左右和均为0,直接返回0。

综合分析

  1. 时间复杂度

    • 输入处理:两次遍历字符串(统计元素、分割填充),O(n)。
    • 总和与检查:两次遍历数组,O(n)。
    • 总体复杂度:O(n),完全适合题目最大规模(1e4元素)。
  2. 空间复杂度

    • 输入字符串缓冲区 O(n),动态数组 O(n),总体 O(n)。
  3. 最优性

    • 必须遍历所有元素才能确定结果,时间复杂度已是最优。
    • 空间复杂度由输入数据决定,无法进一步优化。
  4. 适用场景

    • 处理合法输入格式,自动适应不同长度的数组,边界条件处理正确。

GO

问题分析

我们需要在整数数组中找到第一个左边元素和等于右边元素和的索引。左边和右边的和分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。


解题思路

  1. 输入处理:将输入的逗号分隔字符串转换为整数数组。
  2. 总和计算:遍历数组计算所有元素的总和。
  3. 遍历检查:维护左边累积和,逐个元素计算右边的和,若相等则返回索引。

代码实现

go 复制代码
package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Scan()             // 读取输入行
	input := scanner.Text()    // 获取输入字符串

	// 分割字符串并转为整数数组
	parts := strings.Split(input, ",")
	nums := make([]int, len(parts))
	for i, s := range parts {
		nums[i], _ = strconv.Atoi(s) // 字符串转整数,忽略错误处理
	}

	// 计算总和
	total := 0
	for _, num := range nums {
		total += num
	}

	leftSum := 0 // 初始化左边和为0
	for i, num := range nums {
		rightSum := total - leftSum - num // 右边和计算
		if leftSum == rightSum {          // 找到符合条件的第一个位置
			fmt.Println(i)
			return
		}
		leftSum += num // 更新左边和
	}

	fmt.Println(-1) // 未找到
}

代码详解

  1. 输入处理

    • scanner.Scan() 读取标准输入的一行。
    • strings.Split(input, ",") 将输入字符串按逗号分割成子字符串数组。
    • strconv.Atoi(s) 将每个子字符串转换为整数,构建整数数组 nums
  2. 总和计算

    • 遍历数组 nums,累加所有元素的值到 total
  3. 遍历检查

    • leftSum 初始化为0,表示当前位置左边的累积和。
    • 对每个元素 nums[i]
      • 计算右边和rightSum = total - leftSum - nums[i]
      • 判断条件:若左边和等于右边和,输出索引并终止程序。
      • 更新左边和 :将当前元素值累加到 leftSum

示例测试

示例1

输入:

复制代码
2,5,-1,8,6

输出:

复制代码
3

解析:

  • 总和为 2+5+(-1)+8+6=20
  • 遍历到索引3(元素8)时:
    • leftSum = 2+5+(-1) = 6
    • rightSum = 20 -6 -8 = 6,左右相等,输出3。

示例2

输入:

复制代码
8,9

输出:

复制代码
-1

解析:

  • 总和为17,遍历后无左右和相等的位置。

示例3

输入:

复制代码
11

输出:

复制代码
0

解析:

  • 单元素数组,左右和均为0,直接返回0。

综合分析

  1. 时间复杂度

    • 输入处理:两次遍历字符串(分割和转换),O(n)。
    • 总和与检查:两次遍历数组,O(n)。
    • 总体复杂度:O(n),完全适合题目最大输入规模(1e4元素)。
  2. 空间复杂度

    • 存储输入数组需要 O(n) 空间,其他变量为常数空间。
  3. 最优性

    • 必须遍历所有元素才能确定结果,时间复杂度已是最优。
  4. 适用场景

    • 处理合法输入格式,自动适应不同长度的数组,边界条件处理正确。

更多内容:

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

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

相关推荐
涵信6 分钟前
第十一节:性能优化高频题-响应式数据深度监听问题
javascript·vue.js·性能优化
程序员JerrySUN24 分钟前
驱动开发硬核特训 · Day 21(上篇) 抽象理解 Linux 子系统:内核工程师的视角
java·linux·驱动开发
codingandsleeping31 分钟前
Express入门
javascript·后端·node.js
Vaclee34 分钟前
JavaScript-基础语法
开发语言·javascript·ecmascript
只因只因爆1 小时前
如何在idea中写spark程序
java·spark·intellij-idea
你憨厚的老父亲突然1 小时前
从码云上拉取项目并在idea配置npm时完整步骤
java·npm·intellij-idea
拉不动的猪1 小时前
前端常见数组分析
前端·javascript·面试
全栈凯哥1 小时前
桥接模式(Bridge Pattern)详解
java·设计模式·桥接模式
PXM的算法星球1 小时前
【软件工程】面向对象编程(OOP)概念详解
java·python·软件工程
两点王爷1 小时前
springboot项目文件上传到服务器本机,返回访问地址
java·服务器·spring boot·文件上传