数组重排最小化差值解题思路 | 豆包MarsCode AI 刷题

223 阅读4分钟

数组重排最小化差值

问题描述

小C 和小U 有两个数组,分别是 ab,它们的长度相同。小U 想通过重新排列数组 a 的元素,来最小化 ab 之间的差异。具体来说,他们要最小化所有元素差值绝对值之和,即 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进行求和,使得这个和最小。

观察与分析

  1. 对于两个数值,如果两者越接近,其绝对差值越小。因此,要最小化 sum(abs(a[i] - b[i])),最佳策略是尽可能将数组 a 的值与数组 b 的值对齐。
  2. 对两个数组排序后,让对应位置的元素相减,绝对差值之和会达到最小。这是因为排序保证了大值和小值的匹配,从而减少极端差值的产生。

是不是有一种感觉,总是感觉有能得到更小的结果的算法?

让我们使用几何角度来证明一下,为什么两个数组都是有序之后,对应相减并相加之后得到的就是最好的结果

  1. 假设 ab 是两组点(比如一维坐标轴上的点)。a组点的个数与b组点的个数是一样的。

  2. 排序后,直接匹配最接近的点,意味着连接两点的“线段”最短。

  3. 如果不排序而任意匹配,则可能出现交叉线段的情况:

    • 交叉线段总是比直线段的长度总和更大(类似三角形不等式)。
    • 因此,排序并匹配避免了这种“交叉”,从而保证差值最小。

image-20241125164622832.png

因为在一条轴线上进行作差、连线观察过于不明显,所以在图中使用虚线在轴线上的投影作为数据的差。

算法步骤

  1. 排序:将数组 a 和数组 b 都按升序排序。
  2. 计算差值和:遍历数组 ab,逐一计算对应元素的绝对差值,并将这些差值累加。

时间复杂度

  • 排序:两个数组排序的复杂度是O(nlog⁡n),其中 n 是数组的长度。
  • 计算绝对差值:复杂度为O(n)
  • 总复杂度为 O(nlog⁡n)

总结一下

1. 理解问题的本质

  • 问题核心:如何最小化两个数组中对应元素的绝对差值之和?
  • 本质上:这是一个数学优化问题,目标是通过合理匹配数组元素,减小“极端差值”的影响,找到全局最优解。

通过对问题的分析,可以发现:

  • 越接近的数值之间匹配,绝对差值越小。
  • 将两个数组排序后逐一匹配是最简单且高效的策略,能够避免复杂的计算和极端情况。

2. 排序匹配的意义

  • 排序匹配的简单高效性令人印象深刻。这种方法不仅直观,而且通过贪心思想和数学证明能够确保全局最优解。
  • 排序后按顺序匹配可以避免“大的值和小的值匹配”的问题,从而显著减少总差值。

3. 数学与算法结合的启发

  • 数学证明保证正确性:通过单调性、三角形不等式等数学工具,理解排序匹配为什么是最优的。这种数学思路可以迁移到其他优化问题。
  • 算法实现保证高效性:排序匹配的时间复杂度是O(nlog⁡n),能够快速处理大规模数据,实际应用中非常实用。

关于AI刷题

我觉得 合理地利用MarsCode进行刷题真的有很大优势,特别是效率和系统性。针对于最小化数组差值这道题来说,MarsCode不仅直接告诉我排序匹配是最优的,还结合了一些证明思路和代码详细讲解了为什么这样做是对的。通过MarsCode的讲解,我能快速理解题目本质,让学习更加深入。MarsCode帮助我从分析问题到实现代码,整个过程变得更加高效和清晰。