数组重排最小化差值
问题描述
小C 和小U 有两个数组,分别是 a 和 b,它们的长度相同。小U 想通过重新排列数组 a 的元素,来最小化 a 和 b 之间的差异。具体来说,他们要最小化所有元素差值绝对值之和,即 sum(abs(a[i] - b[i]))。 你能帮助小C 和小U 找到这个最小化的值吗?
测试样例
样例1:
输入:
a = [2, 1, 3, 2], b = [5, 2, 4, 2]输出:5
样例2:
输入:
a = [1, 4, 6], b = [2, 5, 7]输出:3
样例3:
输入:
a = [1, 9, 6], b = [2, 5, 7]输出:4
答案:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
// 求最小化差值的函数
long long solution(vector<int> a, vector<int> b) {
// 对两个数组排序
sort(a.begin(), a.end());
sort(b.begin(), b.end());
long long result = 0;
// 计算对应位置的绝对差的和
for (size_t i = 0; i < a.size(); ++i) {
result += abs(a[i] - b[i]);
}
return result;
}
int main() {
vector<int> a1 = {2, 1, 3, 2}, b1 = {5, 2, 4, 2};
vector<int> a2 = {1, 4, 6}, b2 = {2, 5, 7};
vector<int> a3 = {1, 9, 6}, b3 = {2, 5, 7};
cout << solution(a1, b1) << endl; // 输出 5
cout << solution(a2, b2) << endl; // 输出 3
cout << solution(a3, b3) << endl; // 输出 4
return 0;
}
解题思路
这个问题要求最小化两个数组的绝对差值之和 sum(abs(a[i] - b[i]))。
解题的关键点在于:
a1:a中的一个数字
b1:b中的一个数字
a1-b1=r1,
同样的操作,得到ri,
对ri进行求和,使得这个和最小。
观察与分析
- 对于两个数值,如果两者越接近,其绝对差值越小。因此,要最小化
sum(abs(a[i] - b[i])),最佳策略是尽可能将数组a的值与数组b的值对齐。 - 对两个数组排序后,让对应位置的元素相减,绝对差值之和会达到最小。这是因为排序保证了大值和小值的匹配,从而减少极端差值的产生。
是不是有一种感觉,总是感觉有能得到更小的结果的算法?
让我们使用几何角度来证明一下,为什么两个数组都是有序之后,对应相减并相加之后得到的就是最好的结果
-
假设
a和b是两组点(比如一维坐标轴上的点)。a组点的个数与b组点的个数是一样的。 -
排序后,直接匹配最接近的点,意味着连接两点的“线段”最短。
-
如果不排序而任意匹配,则可能出现交叉线段的情况:
- 交叉线段总是比直线段的长度总和更大(类似三角形不等式)。
- 因此,排序并匹配避免了这种“交叉”,从而保证差值最小。
因为在一条轴线上进行作差、连线观察过于不明显,所以在图中使用虚线在轴线上的投影作为数据的差。
算法步骤
- 排序:将数组
a和数组b都按升序排序。 - 计算差值和:遍历数组
a和b,逐一计算对应元素的绝对差值,并将这些差值累加。
时间复杂度
- 排序:两个数组排序的复杂度是
O(nlogn),其中n是数组的长度。 - 计算绝对差值:复杂度为
O(n)。 - 总复杂度为
O(nlogn)。
总结一下
1. 理解问题的本质
- 问题核心:如何最小化两个数组中对应元素的绝对差值之和?
- 本质上:这是一个数学优化问题,目标是通过合理匹配数组元素,减小“极端差值”的影响,找到全局最优解。
通过对问题的分析,可以发现:
- 越接近的数值之间匹配,绝对差值越小。
- 将两个数组排序后逐一匹配是最简单且高效的策略,能够避免复杂的计算和极端情况。
2. 排序匹配的意义
- 排序匹配的简单高效性令人印象深刻。这种方法不仅直观,而且通过贪心思想和数学证明能够确保全局最优解。
- 排序后按顺序匹配可以避免“大的值和小的值匹配”的问题,从而显著减少总差值。
3. 数学与算法结合的启发
- 数学证明保证正确性:通过单调性、三角形不等式等数学工具,理解排序匹配为什么是最优的。这种数学思路可以迁移到其他优化问题。
- 算法实现保证高效性:排序匹配的时间复杂度是
O(nlogn),能够快速处理大规模数据,实际应用中非常实用。
关于AI刷题
我觉得 合理地利用MarsCode进行刷题真的有很大优势,特别是效率和系统性。针对于最小化数组差值这道题来说,MarsCode不仅直接告诉我排序匹配是最优的,还结合了一些证明思路和代码详细讲解了为什么这样做是对的。通过MarsCode的讲解,我能快速理解题目本质,让学习更加深入。MarsCode帮助我从分析问题到实现代码,整个过程变得更加高效和清晰。