题目
题目解析
最开始读完题,我还得意洋洋的以为,只需要找到,不改变情况下,绝对值差值最大的那个,然后对他进行差值最小的优化。。。
还是太年轻了,这样的贪心完全不对,我们将每一个绝对值差值和他的最优情况的差值进行比较,得出这两个差值的最大值,而不是单纯只考虑到原绝对值差值大。。。
- 错误代码示范
class Solution {
public:
const int MOD = 1e9+7;
int minAbsoluteSumDiff(vector<int>& nums1, vector<int>& nums2) {
int sz = nums1.size();
vector<int>tt(sz);
for(int i=0;i<sz;i++)
tt[i] = abs(nums1[i]-nums2[i]);
int max = INT_MIN,pos;
int res = 0;
//寻找误差差值最大的数,以及它对应的位置(要改肯定也就是改这个数最好)
for(int i=0;i<sz;i++){
if(tt[i]>max){
max = tt[i];
pos = i;
}
res += tt[i];
}
//由于只需要前面的序号对应即可,所以这里能排序查找替换的最佳值
sort(nums1.begin(),nums1.end());
//可以通过二分确定修改为哪个数最好,先选中大于或等于nums2[pos]的第一个值
int p;
int l = 0,r = sz;
while(l<r){
int mid = l+(r-l)/2;
if(nums1[mid]>=nums2[pos])
r = mid;
else{
l = mid+1;
}
}
if(l==sz){
p = abs(nums1[l-1]-nums2[pos]);
}else{
if(nums1[l]==nums2[pos]||l==0)
p = nums2[pos] - nums1[l];
else{
p = min(abs(nums2[pos]-nums1[l]),abs(nums2[pos]-nums1[l-1]));
}
}
res = (res - max+p)%MOD;
return res;
}
};
- 正确做法与思路:
- 我们通过原先的
diff-opt_diff
的方式来寻找那个最需要替换绝对值!!! - 那么
opt_diff
如何求呢?可以通过二分查找找等于nums2[i]
的左边界来寻找每个绝对值的最优解opt_diff
,找到左边界i后,可以根据i的值分情况得到最优解
. - 三种情况:
1.i == 0
2.i==n
3.0<i<n
.这三种特殊情况都可以用两类if分流讨论
:如果i<n
则rec[i] - nums2[i]
一定>=0
,如果i>0
,则nums2[i]-resc[i-1]
一定>=0
,这使得无论是两种特殊情况还是不特殊的情况,都将被考虑到! - 关于模运算细节:模运算的分步过程中,如果出现某步使得
(x)%mod
中的x符号
发生改变,那么这个模运算的分步过程将不再准确,可以在其中添加k倍的mod
使得x符号
不发生改变,从而最终的模运算结果不会出差错。此题由于最后出现了减法,可能会对括号中的正负产生影响,所以直接再加上一个mod,而无论是否改变符号加上mod都不会改变最终的模值。
解题代码
class Solution {
public:
const int mod = 1e9+7;
int minAbsoluteSumDiff(vector<int>& nums1, vector<int>& nums2) {
//用于二分查找最优绝对值差值的备胎
vector<int> rec(nums1);
sort(rec.begin(), rec.end());
int sum = 0, maxn = 0;
int n = nums1.size();
for (int i = 0; i < n; i++) {
int diff = abs(nums1[i] - nums2[i]);
sum = (sum + diff) % mod;
//二分寻找左边界的函数
int j = lower_bound(rec.begin(), rec.end(), nums2[i]) - rec.begin();
if (j < n) {
maxn = max(maxn, diff - (rec[j] - nums2[i]));
}
if (j > 0) {
maxn = max(maxn, diff - (nums2[i] - rec[j - 1]));
}
}
//注意加上mod
return (sum - maxn +mod) % mod;
}
};