2026华为OD机考新系统真题|寻找服务器组的最小差值下表(2026.11.08)

本题要求在服务器负载数组中寻找一个分界点下标,使得其左侧负载和与右侧负载和的绝对差值最小;分界点本身不计入任一集群。通过前缀和思想优化,可在O(n)时间、O(1)空间内求解,核心是动态维护左侧和并推导右侧和(right = total - left - nums[i]),同时处理边界及负数情况。

寻找服务器组的最小差值下表(2026.11.08)

2026年最新华为OD机考题库(按考点分类): 2026年最新华为OD机考题库

题目描述:

某数据中心有 N 台服务器按编号顺序排列,第 i 台服务器当前承载的负载数为 nums[i]。运维系统需要选择一台服务器作为分界点,将其左侧的所有服务器划归为 A 集群,右侧的所有服务器划归为 B 集群(分界点本身不计入任一集群),使得两个集群的负载总量差值绝对值最小,从而实现负载均衡。

若分界点选在最左端,A 集群负载视为 0;选在最右端,B 集群负载视为 0。 若存在多个负载差值最小的分界点,返回最左侧的服务器编号。

输入

整数数组 nums,nums[i] 表示第 i 台服务器的负载数,格式如 [1,7,3,6,5,6]。

输出

一个整数,表示选为分界点的服务器下标(从 0 开始)。

数据范围

  • 1 <= nums.length <= 10^4
  • -1000 <= nums[i] <= 1000

样例

用例输入 1

[1, 7, 3, 6, 5, 6]

用例输出 1

3

用例解释 1

下标 3 左侧=1+7+3=11,右侧=5+6=11,差值 0 最小。

用例输入 2

[1, 2, 3]

用例输出 2

1

用例解释 2

下标0差值5、下标1差值2、下标2差值3,最小是 2 对应下标 1。

用例输入 3

[2, 1, -1]

用例输出 3

0

用例解释 3

下标0差值0、下标1差值3、下标2差值3,最小 0 对应下标 0(最左)。

来源

本题来源于网络、非官方材料、仅供学习交流,侵删




🧠 题解思路

第一步:把题目翻译成公式

设整个数组的总和为 total。当我们把下标 i 作为分界点时:

  • 左侧和 left = nums[0] + nums[1] + … + nums[i-1];
  • 右侧和 right = nums[i+1] + nums[i+2] + … + nums[n-1];
  • 分界点 nums[i] 本身既不属于左边也不属于右边。

因为 total = left + nums[i] + right,所以只要知道 left,就能直接算出 right = total - left - nums[i]。

第二步:直接暴力为什么慢

最直接的做法:对每个下标 i,把左边的数加一遍、右边的数加一遍,再算差值。每个 i 要加 n 次,一共 n × n 次。

慢在哪里?相邻两个分界点的左侧和只差一个数:i 的左侧和是 nums[0…i-1],i+1 的左侧和是 nums[0…i],只多了 nums[i]。每次从头重新加,就是在重复劳动。

第三步:前缀和思想——边走边累加左侧和

“前缀和”指的是数组前若干个数的和。例如 nums = [1, 7, 3]:前 0 个数的和是 0,前 1 个是 1,前 2 个是 1+7 = 8,前 3 个是 8+3 = 11。每个前缀和都等于上一个前缀和再加一个数,所以从左到右走一遍,用一个变量 left 不断累加,就能依次得到每个分界点的左侧和,不必重新求和。

右侧和也不用单独算:设整个数组的总和为 total,因为 total = left + nums[i] + right,所以 right = total - left - nums[i]。

第四步:从左到右扫描,维护左侧和

我们从 i = 0 开始依次尝试每个下标。初始时 left = 0。每处理完一个下标 i,就把 nums[i] 加入 left,这样下一个下标 i+1 的左侧和就准备好了。

对每个 i 计算 diff = |left - right|,如果 diff 比当前记录的最小差值更小,就更新答案下标。注意只有“严格更小”才更新,这样当多个下标差值相同时,会保留更靠左的那个。

第五步:处理边界

i = 0 时 left = 0,right = total - nums[0];i = n-1 时 right = 0。这两种情况公式都自然成立,不需要特判。

用样例 1 走一遍

nums = [1, 7, 3, 6, 5, 6],total = 28。

inums[i]leftright = total-left-nums[i]diff当前最优下标
01027270
17120191
2381792
36111103
45176113
56220223

最终最小差值为 0,对应下标 3,输出 3。

⚠️ 易错点

  • 分界点本身不计入左右任一集群,右侧和要减去 nums[i]。
  • 相同差值时必须保留最左侧下标,因此只在 diff 严格小于当前最小值时更新。
  • nums[i] 可能为负数,不能假设前缀和单调递增,必须逐个下标比较。
  • 虽然 n <= 10^4 时 int 不会溢出,但用 long 保存总和更稳妥。
  • 只有一个元素时,左右两侧都为空,差值为 0,应返回下标 0。

⏱️ 复杂度

时间复杂度:O(n),n <= 10^4,最多约 10^4 次循环,每次常数次运算。
空间复杂度:O(1),只使用 total、left、bestDiff、bestI 等常数个变量。

💻 参考代码(Java)

class Solution {
    public int findBalanceIndex(int[] nums) {
        long total = 0;
        for (int x : nums) total += x;   // 整个数组的总和
        long left = 0;                   // 分界点左侧元素之和
        int bestI = 0;                   // 最优下标,初始为 0
        long bestDiff = -1;              // 最小差值
        for (int i = 0; i < nums.length; i++) {
            long right = total - left - nums[i]; // 右侧和
            long diff = left - right;
            if (diff < 0) diff = -diff;
            // 严格小于才更新,相同差值保留最左侧下标
            if (bestDiff == -1 || diff < bestDiff) {
                bestDiff = diff;
                bestI = i;
            }
            left += nums[i];             // 当前元素加入左侧
        }
        return bestI;
    }
}

💻 参考代码(C++)

class Solution {
public:
    int findBalanceIndex(vector<int>& nums) {
        long long total = 0;
        for (int x : nums) total += x;   // 整个数组的总和
        long long left = 0;              // 分界点左侧元素之和
        int bestI = 0;                   // 最优下标,初始为 0
        long long bestDiff = -1;         // 最小差值
        for (int i = 0; i < (int)nums.size(); ++i) {
            long long right = total - left - nums[i]; // 右侧和
            long long diff = left - right;
            if (diff < 0) diff = -diff;
            // 严格小于才更新,相同差值保留最左侧下标
            if (bestDiff == -1 || diff < bestDiff) {
                bestDiff = diff;
                bestI = i;
            }
            left += nums[i];             // 当前元素加入左侧
        }
        return bestI;
    }
};

💻 参考代码(Python)

class Solution:
    def findBalanceIndex(self, nums):
        total = sum(nums)          # 整个数组的总和
        left = 0                   # 分界点左侧元素之和
        best_i = 0                 # 记录最优下标,初始为 0
        best_diff = None           # 记录最小差值
        for i, x in enumerate(nums):
            right = total - left - x   # 右侧和 = 总和 - 左侧和 - 当前分界点
            diff = abs(left - right)
            # 严格小于才更新,保证相同差值时保留最左侧下标
            if best_diff is None or diff < best_diff:
                best_diff = diff
                best_i = i
            left += x              # 当前元素加入左侧,供下一个分界点使用
        return best_i

💻 参考代码(JavaScript)

class Solution {
    findBalanceIndex(nums) {
        let total = 0;
        for (const x of nums) total += x;   // 整个数组的总和
        let left = 0;                       // 分界点左侧元素之和
        let bestI = 0;                      // 最优下标,初始为 0
        let bestDiff = -1;                  // 最小差值
        for (let i = 0; i < nums.length; i++) {
            const right = total - left - nums[i]; // 右侧和
            let diff = left - right;
            if (diff < 0) diff = -diff;
            // 严格小于才更新,相同差值保留最左侧下标
            if (bestDiff === -1 || diff < bestDiff) {
                bestDiff = diff;
                bestI = i;
            }
            left += nums[i];                // 当前元素加入左侧
        }
        return bestI;
    }
}

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

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值