
2025 A卷 100分 题型
本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式;
并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析;
本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分享》
华为OD机试真题《阿里巴巴找黄金宝箱Ⅰ》:
文章快捷目录
题目描述及说明
Java
python
JavaScript
C
GO
更多内容
题目名称:阿里巴巴找黄金宝箱Ⅰ
- 知识点:前缀和、双指针(或逻辑模拟)
- 时间限制:1秒
- 空间限制:256MB
- 限定语言:不限
题目描述
一贫如洗的樵夫阿里巴巴在去砍柴的路上,无意中发现了强盗集团的藏宝地,藏宝地有编号从0~N的箱子,每个箱子上面贴有一个数字,箱子中可能有一个黄金宝箱。
黄金宝箱满足:排在它之前的所有箱子数字和等于排在它之后的所有箱子数字和;
- 第一个箱子左边部分的数字和定义为0;
- 最后一个宝箱右边部分的数字和定义为0。
请帮阿里巴巴找到黄金宝箱,输出第一个满足条件的黄金宝箱编号,如果不存在黄金宝箱,请返回-1。
输入描述 :
箱子上贴的数字列表,使用逗号分隔,例如:1,-1,0
。
- 宝箱的数量不小于1个,不超过10000;
- 宝箱上贴的数值范围不低于-1000,不超过1000。
输出描述 :
第一个黄金宝箱的编号(从0开始计数)。
示例:
- 输入:
2,5,-1,8,6
,输出:3
- 下标3之前的数字和为:
2 + 5 + -1 = 6
,之后的数字和为:6 = 6
。
- 下标3之前的数字和为:
- 输入:
8,9
,输出:-1
(无满足条件的位置)。 - 输入:
11
,输出:0
(下标0左右和均为0)。
Java
问题分析
我们需要找到数组中第一个满足左边元素和等于右边元素和的索引位置。左边和右边的定义分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。
解题思路
- 总和计算:首先计算数组所有元素的总和。
- 遍历检查 :遍历数组,维护一个累积的左边和
leftSum
。对于每个位置i
,右边的和为totalSum - leftSum - nums[i]
。如果左边和等于右边的和,则返回当前索引。 - 线性时间复杂度:该方法只需两次遍历数组(一次计算总和,一次查找位置),时间复杂度为 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);
}
}
代码详解
-
输入处理:
scanner.nextLine()
读取输入字符串。split(",")
将字符串按逗号分割成字符串数组。- 转换为
int[]
数组nums
。
-
总和计算:
- 遍历数组累加所有元素的值得到
totalSum
。
- 遍历数组累加所有元素的值得到
-
遍历检查:
- 初始化
leftSum
为0,表示当前位置左边的累积和。 - 遍历每个元素
nums[i]
,计算右边的和rightSum
。 - 如果
leftSum
等于rightSum
,输出当前索引并结束程序。 - 否则,将当前元素值加到
leftSum
中,继续下一个元素。
- 初始化
-
结果输出:
- 若遍历结束未找到符合条件的索引,输出-1。
示例测试
示例1 :
输入:2,5,-1,8,6
输出:3
解析:索引3左边和为2+5+(-1)=6,右边和为6,相等。
示例2 :
输入:8,9
输出:-1
解析:两个位置均不满足左边和等于右边和。
示例3 :
输入:11
输出:0
解析:左边和与右边和均为0。
综合分析
- 时间复杂度:两次遍历数组,时间复杂度为 O(n),n为数组长度。对于最大输入规模1e4,完全可行。
- 空间复杂度:除了存储输入数组外,仅使用常数空间。
- 最优性:该方法无法进一步优化时间复杂度,因为必须遍历所有元素才能确定结果。空间复杂度已是最优。
- 适用性:适用于所有合法输入,处理边界条件(如单个元素)正确。
python
问题分析
我们需要找到数组中第一个满足左边元素和等于右边元素和的索引位置。左边和右边的定义分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。
解题思路
- 总和计算 :首先计算数组所有元素的总和
total_sum
。 - 遍历检查 :遍历数组,维护一个累积的左边和
left_sum
。对于每个位置i
,右边的和为total_sum - left_sum - nums[i]
。如果左边和等于右边的和,则返回当前索引。 - 线性时间复杂度:该方法只需两次遍历数组(一次计算总和,一次查找位置),时间复杂度为 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)
代码详解
-
输入处理:
input().strip()
读取输入并去除首尾空格。split(',')
将字符串按逗号分割成多个子字符串。map(int, ...)
将每个子字符串转换为整数,最终生成整数列表nums
。
-
总和计算:
sum(nums)
快速计算数组的总和total_sum
。
-
遍历检查:
left_sum
初始化为0,表示当前元素左边的累积和。- 遍历每个元素
nums[i]
:right_sum = total_sum - left_sum - current
:右边的和为总和减去左边和和当前元素值。- 如果
left_sum == right_sum
,直接输出当前索引并终止程序。 - 否则将当前元素值累加到
left_sum
,继续处理下一个元素。
-
结果输出:
- 若遍历结束未找到符合条件的索引,输出-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=0
,right_sum=17-0-8=9
(0≠9)。 - 索引1:
left_sum=8
,right_sum=17-8-9=0
(8≠0),无解。
示例3 :
输入:
11
输出:
0
解析:
- 总和为11。
- 索引0:
left_sum=0
,right_sum=11-0-11=0
,满足条件。
综合分析
-
时间复杂度:
- 计算总和:一次遍历,O(n)。
- 遍历检查:一次遍历,O(n)。
- 总体复杂度:O(n),完全适合题目中的最大输入规模(1e4)。
-
空间复杂度:
- 仅需存储输入数组和几个临时变量,空间复杂度为 O(1)。
-
最优性:
- 这是最优解法,因为必须遍历所有元素才能确保找到第一个符合条件的索引,无法进一步优化时间复杂度。
-
适用场景:
- 处理单个或多个元素的场景均正确,能高效处理边界条件(如数组仅一个元素)。
JavaScript
问题分析
我们需要找到数组中第一个满足左边元素和等于右边元素和的索引位置。左边和右边的定义分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。
解题思路
- 总和计算 :首先计算数组所有元素的总和
totalSum
。 - 遍历检查 :遍历数组,维护一个累积的左边和
leftSum
。对于每个位置i
,右边的和为totalSum - leftSum - nums[i]
。如果左边和等于右边的和,则返回当前索引。 - 线性时间复杂度:该方法只需两次遍历数组(一次计算总和,一次查找位置),时间复杂度为 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();
});
代码详解
-
输入处理:
input.split(',')
将输入的字符串按逗号分割成字符串数组。map(Number)
将每个字符串转换为数字,生成数字数组nums
。
-
总和计算:
reduce((acc, curr) => acc + curr, 0)
遍历数组累加所有元素的值,得到总和totalSum
。
-
遍历检查:
- 初始化
leftSum
为0,表示当前元素左边的累积和。 - 遍历每个元素
nums[i]
:rightSum = totalSum - leftSum - current
:右边的和为总和减去左边和和当前元素值。- 如果
leftSum === rightSum
,直接输出当前索引并结束程序。 - 否则将当前元素值累加到
leftSum
,继续处理下一个元素。
- 初始化
-
结果输出:
- 若遍历结束未找到符合条件的索引,输出-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=0
,rightSum=17-0-8=9
(0≠9)。 - 索引1:
leftSum=8
,rightSum=17-8-9=0
(8≠0),无解。
示例3 :
输入:
11
输出:
0
解析:
- 总和为11。
- 索引0:
leftSum=0
,rightSum=11-0-11=0
,满足条件。
综合分析
-
时间复杂度:
- 计算总和:一次遍历,O(n)。
- 遍历检查:一次遍历,O(n)。
- 总体复杂度:O(n),完全适合题目中的最大输入规模(1e4)。
-
空间复杂度:
- 仅需存储输入数组和几个临时变量,空间复杂度为 O(1)。
-
最优性:
- 这是最优解法,因为必须遍历所有元素才能确保找到第一个符合条件的索引,无法进一步优化时间复杂度。
-
适用场景:
- 处理单个或多个元素的场景均正确,能高效处理边界条件(如数组仅一个元素)。
C++
问题分析
我们需要在整数数组中找到第一个满足左边元素和等于右边元素和的索引。左边和右边的和分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。
解题思路
- 输入处理:将输入的逗号分隔字符串转换为整数数组。
- 总和计算:遍历数组计算所有元素的总和。
- 遍历检查:维护左边累积和,逐个元素计算右边的和,若相等则返回索引。
代码实现
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;
}
代码详解
-
输入处理:
getline(cin, input)
:读取整行输入。stringstream
分割字符串为子字符串,通过stoi
转换为整数存入nums
。
-
总和计算:
- 遍历数组,累加所有元素的值到
totalSum
。
- 遍历数组,累加所有元素的值到
-
遍历检查:
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。
综合分析
-
时间复杂度:
- 总和计算:一次遍历,O(n)。
- 遍历检查:一次遍历,O(n)。
- 总体复杂度:O(n),适合最大输入规模1e4。
-
空间复杂度:
- 存储输入数组的 O(n) 空间,其他变量为常数空间。
-
最优性:
- 必须遍历所有元素才能确定结果,无法进一步优化时间复杂度。
-
适用场景:
- 处理单个或多个元素均正确,边界条件处理得当。
C
问题分析
我们需要在整数数组中找到第一个满足左边元素和等于右边元素和的索引。左边和右边的和分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。
解题思路
- 输入处理:读取逗号分隔的字符串,转换为整数数组。
- 总和计算:遍历数组计算所有元素的总和。
- 遍历检查:维护左边累积和,逐个元素计算右边的和,若相等则返回索引。
代码实现
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;
}
代码详解
-
输入处理:
fgets
读取输入到input
缓冲区。- 去除末尾的换行符,确保字符串正确分割。
-
计算元素数量:
- 遍历字符串统计逗号数量,元素数量为逗号数+1。
-
动态分配数组:
- 根据计算的
count
分配足够内存存储整数数组。
- 根据计算的
-
分割字符串填充数组:
strtok
按逗号分割字符串,逐个转换为整数存入数组。
-
总和计算:
- 遍历数组累加所有元素,得到总和
totalSum
。
- 遍历数组累加所有元素,得到总和
-
遍历检查:
- 维护
leftSum
表示当前位置左边的累积和。 - 对每个元素计算
rightSum
,若等于leftSum
,输出索引并终止。 - 否则更新
leftSum
并继续遍历。
- 维护
-
内存释放:
- 使用
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。
综合分析
-
时间复杂度:
- 输入处理:两次遍历字符串(统计元素、分割填充),O(n)。
- 总和与检查:两次遍历数组,O(n)。
- 总体复杂度:O(n),完全适合题目最大规模(1e4元素)。
-
空间复杂度:
- 输入字符串缓冲区 O(n),动态数组 O(n),总体 O(n)。
-
最优性:
- 必须遍历所有元素才能确定结果,时间复杂度已是最优。
- 空间复杂度由输入数据决定,无法进一步优化。
-
适用场景:
- 处理合法输入格式,自动适应不同长度的数组,边界条件处理正确。
GO
问题分析
我们需要在整数数组中找到第一个左边元素和等于右边元素和的索引。左边和右边的和分别为该位置前所有元素的和及该位置后所有元素的和。若不存在这样的位置,返回-1。
解题思路
- 输入处理:将输入的逗号分隔字符串转换为整数数组。
- 总和计算:遍历数组计算所有元素的总和。
- 遍历检查:维护左边累积和,逐个元素计算右边的和,若相等则返回索引。
代码实现
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) // 未找到
}
代码详解
-
输入处理:
scanner.Scan()
读取标准输入的一行。strings.Split(input, ",")
将输入字符串按逗号分割成子字符串数组。strconv.Atoi(s)
将每个子字符串转换为整数,构建整数数组nums
。
-
总和计算:
- 遍历数组
nums
,累加所有元素的值到total
。
- 遍历数组
-
遍历检查:
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。
综合分析
-
时间复杂度:
- 输入处理:两次遍历字符串(分割和转换),O(n)。
- 总和与检查:两次遍历数组,O(n)。
- 总体复杂度:O(n),完全适合题目最大输入规模(1e4元素)。
-
空间复杂度:
- 存储输入数组需要 O(n) 空间,其他变量为常数空间。
-
最优性:
- 必须遍历所有元素才能确定结果,时间复杂度已是最优。
-
适用场景:
- 处理合法输入格式,自动适应不同长度的数组,边界条件处理正确。
更多内容:
https://www.kdocs.cn/l/cvk0eoGYucWA
本文发表于【纪元A梦】,关注我,获取更多实用教程/资源!