华为OD机试 - 均衡调度 - 数学推导(Java 新系统 100分)

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

在这里插入图片描述

华为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 开始),规则说明:

  1. 单个任务耗时取值 0 < T < 100 0 < T < 100 0<T<100。

  2. 用例保证均有解,且满足条件的下标对 [ i , j ] [i,j] [i,j] 唯一。

  3. 队列 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算法的适用场景,发现新题目,随时更新,全天优快云在线答疑。

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值