leetcode
leetcode 1601 ~ 1650
绝对差值和

绝对差值和

难度:

标签:

题目描述

代码结果

运行时间: 104 ms, 内存: 29.4 MB


/*
 * 思路:
 * 1. 计算初始的绝对差值和。
 * 2. 使用流操作来找到能够最小化绝对差值和的替换值。
 * 3. 计算最大可能的差值减少。
 * 4. 返回最小化的绝对差值和,对 10^9 + 7 取余。
 */

import java.util.Arrays;

public class MinAbsoluteSumDiffStream {
    public int minAbsoluteSumDiff(int[] nums1, int[] nums2) {
        int MOD = 1_000_000_007;
        int[] sortedNums1 = Arrays.stream(nums1).sorted().toArray();
        int initialDiff = Arrays.stream(nums1).map(i -> Math.abs(i - nums2[i])).sum() % MOD;

        int maxDiffReduction = Arrays.stream(nums1).map(i -> {
            int diff = Math.abs(nums1[i] - nums2[i]);
            int closestIdx = Arrays.binarySearch(sortedNums1, nums2[i]);

            if (closestIdx < 0) closestIdx = -(closestIdx + 1);

            int minDiff = Integer.MAX_VALUE;
            if (closestIdx < sortedNums1.length) minDiff = Math.min(minDiff, Math.abs(sortedNums1[closestIdx] - nums2[i]));
            if (closestIdx > 0) minDiff = Math.min(minDiff, Math.abs(sortedNums1[closestIdx - 1] - nums2[i]));

            return diff - minDiff;
        }).max().getAsInt();

        return (initialDiff - maxDiffReduction + MOD) % MOD;
    }
}

解释

方法:

此题解的策略是首先计算出原始数组 nums1 和 nums2 之间的绝对差值和。然后尝试通过替换 nums1 中的每个元素来找到可能降低这个差值和的最大幅度。为了实现这一点,我们首先对 nums1 进行排序,以便于后续可以快速找到最接近 nums2 中任意元素 b 的 nums1 中的元素。对于 nums1 和 nums2 中的每个元素对 (a, b),我们计算原始差值 t = |a - b| 并累加到总和 ret 中。接着,使用二分搜索在排序后的 nums1 中查找最接近 b 的元素,计算如果替换了这个元素后的新差值 nt。我们记录下所有可能的替换中,减少的最大差值 r。最终答案即为原始差值和减去这个最大减少值 r,并对 10^9+7 取余。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在尝试最小化绝对差值和时,只考虑替换nums1中的单一元素,而不是多个元素?
尽管同时替换多个元素可能会进一步降低绝对差值和,但这样会大幅增加问题的复杂性和计算量。考虑到每个元素都有多种替换可能,同时替换多个元素会导致情况组合指数级增长,这在算法设计中是不可行的。因此,我们通常采用贪心策略,即通过每次只替换一个元素来寻找最佳单次替换,从而在可接受的时间复杂度内获得一个较优解。
🦆
在实施二分搜索查找最接近nums2中元素b的nums1元素时,如果有多个相同的最小差值,该如何选择?
如果在使用二分搜索找到多个具有相同最小差值的元素,通常选择任何一个都可以,因为它们提供相同的差值减少。然而,为了保持一致性和可能的最小化边际效应,通常选择第一个找到的或者位置最靠前的元素。这样做可以保持算法的简洁性和实现的直观性。
🦆
题解中提到使用排序和二分搜索来优化查找过程,这种方法与直接遍历nums1中的每个元素相比,效率提升在哪里?
通过对nums1进行排序和使用二分搜索,我们将查找最接近的元素的时间复杂度从O(n)降低到O(log n)。这意味着对于每个元素b,我们可以以对数时间复杂度找到接近的值,而不是线性时间。因此,整体算法的时间复杂度从O(n^2)(对于每对元素进行遍历)降低到O(n log n)(排序nums1和对每个元素b进行二分搜索)。这显著提高了算法处理大数据集的能力。
🦆
为什么在计算最大减少量r时,需要检查当前的差值t是否大于已记录的最大减少量r,这一步的逻辑依据是什么?
在计算最大减少量r时,检查当前差值t是否大于已记录的最大减少量r是为了确保我们只考虑那些能实现最大绝对差值减少的元素替换。如果当前差值t本身就不大,即使通过替换减少了差值,也不会对总和产生显著影响。因此,我们专注于那些原始差值较大的情况,通过尝试替换来达到最大的减少效果。这种方法可以更有效地减少总的绝对差值和。

相关问题