
华为OD机试 新系统 题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试(JAVA)真题》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天优快云在线答疑。
一、题目内容
已知存在两个任务队列 A A A、 B B B,队列成员表示单个任务耗时;为了缩短整体运行时间,需要队列 A A A 和队列 B B B 中任务的总耗时一致。
初始时队列 A A A 和队列 B B B 的任务总耗时不同,要求只进行一次任务交换:从 A A A 中选择一个任务,从 B B B 中选择一个任务,两者互换;交换后要求两个队列的任务总耗时相等。
请你找出队列 A A A 和队列 B B B 中需要交换的任务位置 [ i , j ] [i,j] [i,j](数组下标,从 0 开始),规则说明:
-
单个任务耗时取值 0 < T < 100 0 < T < 100 0<T<100。
-
用例保证均有解,且满足条件的下标对 [ i , j ] [i,j] [i,j] 唯一。
-
队列 A A A 和队列 B B B 长度为 1 ∼ 50 1 \sim 50 1∼50。
二、输入描述
整型数组 A A A,由队列 A A A 中的任务耗时构成的数组。
整型数组 B B B,由队列 B B B 中的任务耗时构成的数组。
三、输出描述
数组 [ i , j ] [i,j] [i,j],其中 i i i 是 A A A 中参与交换任务的原始下标, j j j 是 B B B 中参与交换任务的原始下标,下标从 0 开始。
四、测试用例
测试用例1:
1、输入
1,2,9
1,2,3,4
2、输出
1,0
3、说明
基础场景:A 总耗时大于 B
初始总耗时为 12 和 10。交换 A[1]=2 与 B[0]=1 后,两个队列的总耗时均变为 11。
测试用例2:
1、输入
1,15,9
2,4,6,8,25
2、输出
1,4
3、说明
反向场景:A 总耗时小于 B
初始总耗时为 25 和 45。交换 A[1]=15 与 B[4]=25 后,两个队列的总耗时均变为 35。验证负数差值的处理。
五、解题思路
解题思路:数学推导 + 定长数组映射
1、数学公式推导
首先遍历两个任务队列,计算总耗时 sumA 和 sumB。假设交换的任务分别为 A[i] 和 B[j],交换后两个队列总耗时相等,即:
sumA - A[i] + B[j] = sumB - B[j] + A[i]
整理得到:
A[i] - B[j] = (sumA - sumB) / 2
因此,当确定 A 中的任务时,可以直接计算 B 中需要匹配的任务耗时,而不必枚举所有交换组合。
2、数据结构选择
由于题目规定单个任务耗时在 1~99 之间,采用长度为 100 的整型数组 indexInB 建立映射。数组下标表示任务耗时,数组元素表示该任务在 B 中的原始下标。
初始化所有元素为 -1,表示对应耗时不存在。遍历 B,将每个任务的原始下标记录下来。
该结构比普通哈希表更简单,没有哈希冲突问题,且能够直接按耗时进行常数时间查找。
3、算法实现
遍历队列 A,对每个位置 i,计算目标耗时:
target = A[i] - (sumA - sumB) / 2
检查 target 是否在 1~99 范围内,以及 indexInB[target] 是否不为 -1。如果满足条件,则返回 [i, indexInB[target]]。
若两个队列总耗时之差为奇数,则无法通过交换整数任务达到平衡。题目保证存在唯一解,因此正常情况下总能找到结果。
4、正确性与复杂度
算法完全依据交换后总耗时相等的充要条件查找,因此找到的下标对一定满足要求。
相比 O(n×m) 的双重循环,数组映射避免了重复比较;相比排序算法,不会改变任务的原始下标。
- 时间复杂度:O(n+m+100),即 O(n+m)。
- 空间复杂度:O(100),即 O(1)。
- n、m 分别为两个任务队列的长度。
该算法实现简单、性能稳定,适合本题给定的数据范围。
六、Java算法源码
import java.util.Arrays;
import java.util.Scanner;
public class OdTest {
// 将逗号分隔的字符串转换为整数数组,兼容逗号两侧的空格
private static int[] parseArray(String line) {
String[] parts = line.trim().split("\\s*,\\s*");
int[] arr = new int[parts.length];
for (int i = 0; i < parts.length; i++) {
arr[i] = Integer.parseInt(parts[i]);
}
return arr;
}
private static int[] findSwap(int[] a, int[] b) {
int sumA = 0;
int sumB = 0;
// 第一步:计算两个队列的总耗时
for (int x : a) {
sumA += x;
}
for (int y : b) {
sumB += y;
}
// 第二步:根据交换后总耗时相等的条件推导:
// sumA - a[i] + b[j] = sumB - b[j] + a[i]
// 变形得到:
// a[i] - b[j] = (sumA - sumB) / 2
int diff = sumA - sumB;
// 差值为奇数时,不可能通过交换两个整数任务达到平衡
if (diff % 2 != 0) {
return new int[]{-1, -1};
}
int half = diff / 2;
// 第三步:建立任务耗时到 B 中原始下标的映射
// 题目规定任务耗时为 1~99,因此数组长度取 100
// indexInB[t] 表示耗时为 t 的任务在 B 中的下标
// -1 表示 B 中不存在对应耗时的任务
int[] indexInB = new int[100];
Arrays.fill(indexInB, -1);
for (int j = 0; j < b.length; j++) {
indexInB[b[j]] = j;
}
// 第四步:依次遍历 A,寻找 B 中能够使总耗时相等的任务
for (int i = 0; i < a.length; i++) {
// 根据公式直接计算需要在 B 中寻找的任务耗时
int target = a[i] - half;
// 先检查耗时是否符合范围,再检查 B 中是否存在
// 使用数组直接访问,无需双重循环
if (target > 0 && target < 100
&& indexInB[target] != -1) {
// 找到满足条件的任务,返回两个原始下标
return new int[]{i, indexInB[target]};
}
}
// 题目保证存在唯一解,正常情况下不会执行到这里
return new int[]{-1, -1};
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 输入第一行:队列 A
int[] a = parseArray(scanner.nextLine());
// 输入第二行:队列 B
int[] b = parseArray(scanner.nextLine());
// 计算需要交换的任务下标
int[] result = findSwap(a, b);
// 按照题目要求输出:i,j
System.out.println(result[0] + "," + result[1]);
scanner.close();
}
}
七、效果展示
1、输入
4,4,11
1,1,6,1
2、输出
2,2
3、说明
重复元素场景
两个队列均包含重复任务耗时,但有效交换位置仍唯一。交换 A[2]=11 与 B[2]=6 后,总耗时从 19、9 变为 14、14。

🏆下一篇:华为OD机试 - 简易内存池 - 逻辑分析(Java 新系统 200分)
🏆本专栏收录于《华为OD机试(JAVA)真题》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天优快云在线答疑。

本博客解析华为OD机试真题'均衡调度',核心是通过一次任务交换使两队列总耗时相等。采用数学推导得出交换条件:target = (sumA - sumB) / 2 + b_j,结合定长数组(长度100)实现O(1)耗时查找,避免哈希冲突。算法时间复杂度O(n+m),空间复杂度O(1),适用于任务耗时范围0<T<100的约束场景。
19万+

被折叠的 条评论
为什么被折叠?



