寻找服务器组的最小差值下表(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。
| i | nums[i] | left | right = total-left-nums[i] | diff | 当前最优下标 |
|---|---|---|---|---|---|
| 0 | 1 | 0 | 27 | 27 | 0 |
| 1 | 7 | 1 | 20 | 19 | 1 |
| 2 | 3 | 8 | 17 | 9 | 2 |
| 3 | 6 | 11 | 11 | 0 | 3 |
| 4 | 5 | 17 | 6 | 11 | 3 |
| 5 | 6 | 22 | 0 | 22 | 3 |
最终最小差值为 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 };
本题要求在服务器负载数组中寻找一个分界点下标,使得其左侧负载和与右侧负载和的绝对差值最小;分界点本身不计入任一集群。通过前缀和思想优化,可在O(n)时间、O(1)空间内求解,核心是动态维护左侧和并推导右侧和(right = total - left - nums[i]),同时处理边界及负数情况。
2264

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



