1. 概述
本文将介绍磁带平衡问题(Tape Equilibrium Problem)并提供高效的Java解决方案。这是个经典的面试题,核心思路是识别数组的平衡索引。这里的"磁带"是对数字序列的物理比喻——将其切成两部分后,我们的目标是找到使两部分和差异最小的分割点。
2. 问题陈述
给定一个大小为N(N≥2)的整数数组A,在任意位置P(0<P<N)分割数组,形成两个非空部分,求两部分和的最小绝对差值。
以数组 {-1, 6, 8, -4, 7}
为例:
-
|A[0] – (A[1]+A[2]+A[3]+A[4])| = |(-1) – (6+8-4+7)| = 18
-
|(A[0]+A[1]) – (A[2]+A[3]+A[4])| = |(-1+6) – (8-4+7)| = 6
-
|(A[0]+A[1]+A[2]) – (A[3]+A[4])| = |(-1+6+8) – (-4+7)| = 10
-
|(A[0]+A[1]+A[2]+A[3]) – A[4]| = |(-1+6+8-4) – 7| = 2
最小差值是2,因此该数组的磁带平衡值为2。通常,索引较小部分的和称为左和,较大部分的和称为右和。
3. 算法设计
❌ 朴素解法:遍历每个分割点,分别计算左右和再求差。这种做法需要嵌套循环,复杂度达O(N²),性能太差。
✅ 优化方案:预计算部分和数组。部分和数组中索引i的值等于原数组中所有索引≤i的元素之和。这样右和可直接通过 总和 - 左和
快速得出:
右和 = A[i+1] + ... + A[N-1]
= (A[0]+...+A[N-1]) - (A[0]+...+A[i])
= 总和 - 左和
整个算法只需两次数组遍历(计算部分和 + 求最小差值),时间复杂度优化为O(N)。
4. 计算部分和数组
下面代码生成部分和数组,索引i处的值是原数组前i+1个元素的和:
int[] partialSums = new int[array.length];
partialSums[0] = array[0];
for (int i = 1; i < array.length; i++) {
partialSums[i] = partialSums[i - 1] + array[i];
}
5. 计算指定索引的绝对差值
利用部分和数组计算任意索引i的左右和差值。注意:
- 总和 =
partialSums[partialSums.length - 1]
- 右和 = 总和 - 左和
int absoluteDifferenceAtIndex(int[] partialSums, int index) {
return Math.abs((partialSums[partialSums.length - 1] - partialSums[index]) - partialSums[index]);
}
6. 获取磁带平衡值
整合前述步骤的完整解决方案:
int calculateTapeEquilibrium(int[] array) {
// 计算部分和数组
int[] partialSums = new int[array.length];
partialSums[0] = array[0];
for (int i = 1; i < array.length; i++) {
partialSums[i] = partialSums[i - 1] + array[i];
}
// 初始化最小差值(第一个分割点)
int minimalDifference = absoluteDifferenceAtIndex(partialSums, 0);
// 遍历所有可能的分割点
for (int i = 1; i < array.length - 1; i++) {
minimalDifference = Math.min(minimalDifference,
absoluteDifferenceAtIndex(partialSums, i));
}
return minimalDifference;
}
测试用例验证:
@Test
void whenCalculateTapeEquilibrium_thenReturnMinimalDifference() {
int[] array = {-1, 6, 8, -4, 7};
assertEquals(2, new TapeEquilibriumSolver().calculateTapeEquilibrium(array));
}
7. 总结
我们用Java高效解决了磁带平衡问题,核心在于:
- ✅ 通过部分和数组避免重复计算
- ✅ 将复杂度从O(N²)优化到O(N)
- ⚠️ 注意边界条件:分割点范围是
0 < P < N
这种预计算策略在数组求和类问题中非常实用,面试时遇到类似问题可以优先考虑。