力扣 1818. 绝对差值和

题目来源:https://leetcode-cn.com/problems/minimum-absolute-sum-difference/

大致题意:
给定两个长度相同的数组,在最多改动(将某个位置元素用另一位置元素替代)数组一其中一个元素的情况下,求得两数组相同位置元素的所有绝对值和的最小值。

思路

改动前的绝对值和:

  • | nums1[i] - nums2[i] | 的所有和

改动后的绝对值和:

即某个位置的元素被另一位置元素替代,改动后该位置的绝对值为

  • | nums1[j] - nums2[i] |,j即为替换元素位置,i为被替换元素位置

改动前后的差值为:

  • | nums1[i] - nums2[i] | - | nums1[j] - nums2[i] |

若想找到绝对值和的最小值,那么即为上述差值的最大值。因为差值越大,代表原绝对值减去的值也就越大,那么绝对值和自然也就是最小的。

那么解题思路就可为:求出原绝对值和 Sum + 求出最大的上述差值
然后使用 Sum - 最大差值,即为所求答案

排序加二分查找

那么在刚刚的分析结果下,可以先对 nums1 数组进行排序,然后在 | nums1[i] - nums2[i] |已知的情况下,求出最小的 | nums1[j] - nums2[i] |,也就是在排序后的 nums1 数组中二分查找 nums2[i] 最相近的值

而这个最相近的值,有三种可能性:

  • 和 nums2[i] 相同
  • 比 nums2[i] 小
  • 比 nums2[i] 大

而二分的思路,若有相同,返回的索引即为该相同元素位置索引;

public int binarySearch(int[] nums, int num) {
        int low = 0;
        int high = nums.length;
        while (low < high) {
            int mid = (low + high) / 2;
            if (nums[mid] < num) { // 若当前位置小于目标值,二分查找右半段
                low = mid + 1;
            }
            else {
                high = mid;
            }
        }
        return low;
    }

若不相同,那么返回的索引即为大一级元素的索引,于是返回索引即为大的位置索引,返回索引 - 1 即为小的元素索引。
于是可以对比一下两个元素哪个是和nums2[i]最相近的值。
代码如下:

public int minAbsoluteSumDiff(int[] nums1, int[] nums2) {
        int maxSum = 0;
        final int mod = 1000000007;
        int[] sortedNums = new int[nums1.length];
        System.arraycopy(nums1, 0, sortedNums, 0, nums1.length); // 数组内存拷贝
        Arrays.sort(sortedNums); // 排序
        int maxDiff = 0;
        for (int i = 0; i < nums1.length; i++) {
            int diff = Math.abs(nums1[i] - nums2[i]); // 当前差值
            maxSum = (maxSum + diff) % mod;
            int idx = binarySearch(sortedNums, nums2[i]); // 在排序后的数组中查找和nums2[i]最相近的值

            if (idx < nums1.length) { // 如果索引位置未超出数组长度
                maxDiff = Math.max(maxDiff, diff - Math.abs(sortedNums[idx] - nums2[i]));
            }
            if (idx > 0) { // 如果索引位置不为首元素
                maxDiff = Math.max(maxDiff, diff - Math.abs(nums2[i] - sortedNums[idx-1]));
            }
        }
        
        
        return (maxSum - maxDiff + mod) % mod;
    }
上一篇:力扣——合并两个有序数组


下一篇:【leetcode】 两个数组的交集 IIc++