题目
给你两个正整数数组 nums1 和 nums2 ,数组的长度都是 n 。
数组 nums1 和 nums2 的 绝对差值和 定义为所有 |nums1[i] - nums2[i]|(0 <= i < n)的 总和(下标从 0 开始)。
你可以选用 nums1 中的 任意一个 元素来替换 nums1 中的 至多 一个元素,以 最小化 绝对差值和。
在替换数组 nums1 中最多一个元素 之后 ,返回最小绝对差值和。因为答案可能很大,所以需要对 10^9 + 7 取余 后返回。
|x| 定义为:
如果 x >= 0 ,值为 x ,或者
如果 x <= 0 ,值为 -x示例 1:
输入:nums1 = [1,7,5], nums2 = [2,3,5]
输出:3
解释:有两种可能的最优方案:
- 将第二个元素替换为第一个元素:[1,7,5] => [1,1,5] ,或者
- 将第二个元素替换为第三个元素:[1,7,5] => [1,5,5]
两种方案的绝对差值和都是 |1-2| + (|1-3| 或者 |5-3|) + |5-5| = 3示例 2:
输入:nums1 = [2,4,6,8,10], nums2 = [2,4,6,8,10]
输出:0
解释:nums1 和 nums2 相等,所以不用替换元素。绝对差值和为 0示例 3:
输入:nums1 = [1,10,4,4,2,7], nums2 = [9,3,5,1,7,4]
输出:20
解释:将第一个元素替换为第二个元素:[1,10,4,4,2,7] => [10,10,4,4,2,7]
绝对差值和为 |10-9| + |10-3| + |4-5| + |4-1| + |2-7| + |7-4| = 20提示:
n == nums1.length
n == nums2.length
1 <= n <= 10^5
1 <= nums1[i], nums2[i] <= 10^5来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-absolute-sum-difference
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
只允许替换中的一个数字,使得差的绝对值之和最小,那么就要使替换后差绝对值减小最小。
因此,有如下思路:对于中的每一个数,在
中找到和它最接近的数(可以使用二分或者有序集合查找),将找到的这个数替换
中同下标的数,这样在这个位置一定是减小最多的,然后找到其中减小最多的,返回所有的差绝对值之和减去这个最大值。
代码
class Solution {
public int minAbsoluteSumDiff(int[] nums1, int[] nums2) {
int mod = (int) (1e9 + 7);
int n = nums1.length;
// 要对nums1排序,这里复制一份nums
int[] nums = Arrays.copyOf(nums1, n);
Arrays.sort(nums);
// 最大能减小的绝对差值
int maxDec = 0;
int ans = 0;
for (int i = 0; i < n; i++) {
// diff为替换nums[i]之前的绝对差值
int diff = Math.abs(nums1[i] - nums2[i]);
ans = (ans + diff) % mod;
// smallerDiff为替换nums1[i]之后更小的绝对差值
int smallerDiff = bsearch(nums, nums2[i]);
// diff - smallerDiff 为减小的绝对差值
if (diff - smallerDiff > maxDec) {
maxDec = diff - smallerDiff;
}
}
// 这里要注意,由于ans在循环中不断对mod取余,这里ans可能小于maxDec,因此要加一个mod再取余
return (ans - maxDec + mod) % mod;
}
// 找到nums中和target最接近的数x,并返回x和target的绝对差值
public int bsearch(int[] nums, int target) {
int n = nums.length;
int low = 0;
int high = n;
while (low < high) {
int mid = low + (high - low) / 2;
if (nums[mid] < target) {
low = mid + 1;
} else {
high = mid;
}
}
if (low == n) {
return target - nums[n - 1];
}
if (low == 0) {
return nums[0] - target;
}
return Math.min(Math.abs(nums[low - 1] - target), Math.abs(nums[low] - target));
}
}