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

68 阅读3分钟

问题描述

小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

解题思路

  1. 核心目标
    通过匹配数组 ab 中的元素,使得匹配的差值绝对值总和最小。

  2. 步骤

    • 对数组 ab 排序。
    • 使用双指针方法,将两个数组的元素一一匹配,计算差值并累加到结果中。
    • b 中的元素进行计数以处理重复值。

为什么从小到大排序后得到的差值最小

贪心思想

排序的核心思想是:把小的数尽量匹配小的数,大的数尽量匹配大的数

假设我们在两个数组中随意匹配(未排序),可能会导致较小的数字与较大的数字匹配,这样会使得差值变得更大。而通过排序后,从小到大匹配,可以让每一步的差值保持局部最优,进而整体最优。


数学证明

排序后,数组元素按照从小到大的顺序排列,我们希望找到两个数组之间的最小差值总和 ∑∣a[i]−b[j]∣。可以证明:

  1. 如果排序后的 a 和 b 是单调递增的,那么 a[i] 对应 b[i] 是全局最优匹配。
  2. 反例证明:若 a[i] 对应 b[j] 且 i≠j,我们交换 b[i] 和 b[j] 后,差值总和一定不会减小。

交换的反例证明

假设两数组未排序:

  • 数组 a={1,4,6}
  • 数组 b={7,2,5}

随机匹配:(1,7),(4,2),(6,5),差值总和为:

∣1−7∣+∣4−2∣+∣6−5∣=6+2+1=9

排序后匹配:

  • 排序 a={1,4,6},b={2,5,7}
  • 匹配:(1,2),(4,5),(6,7),差值总和为:

∣1−2∣+∣4−5∣+∣6−7∣=1+1+1=3

结论:通过排序后匹配,相同位置的元素差值是最小的,累加总和也就最小。


直观理解

  1. 假设 a[i] 对应的是 b[j],而 a[i+1] 对应的是 b[j+1]。如果 b[j]>b[j+1],交换 b[j]b[j]b[j] 和 b[j+1],差值只会变小。
  2. 按照排序后逐一匹配,能够避免大的数匹配小的数带来的巨大差值。

代码实现(java版)


import java.util.Arrays;

public class Main {
    public static long solution(int[] a, int[] b) {

        // 1. 对数组 a 和 b 排序
        Arrays.sort(a);
        Arrays.sort(b);

        // 2. 使用双指针计算最小差值
        int i = 0; // 指向数组 a
        int j = 0; // 指向数组 b
        long result = 0; // 累加最小差值

        while (i < a.length && j < b.length) {
            result += Math.abs(a[i] - b[j]); // 累加当前最小差值
            i++; // 移动指针 i
            j++; // 移动指针 j
        }

        return result;
    }

    public static void main(String[] args) {
        System.out.println(solution(new int[]{2, 1, 3, 2}, new int[]{5, 2, 4, 2}) == 5);
        // System.out.println(solution(new int[]{1, 4, 6}, new int[]{2, 5, 7}) == 3);
        // System.out.println(solution(new int[]{1, 9, 6}, new int[]{2, 5, 7}) == 4);
    }
}

代码解析

  1. 排序

    • 通过排序,将两个数组的元素从小到大排列,确保后续匹配时差值最小。
  2. 双指针匹配

    • 分别使用指针 ij 遍历两个数组,同时匹配相应元素。
    • 由于两个数组已排序,直接逐个匹配的差值总是局部最优解。
  3. 时间复杂度

    • 排序的复杂度为 O(nlog⁡n)
    • 双指针遍历的复杂度为 O(n)
    • 总复杂度为 O(nlog⁡n)