绝对和差值:二分与贪心思想的联合考察

博客探讨了一道编程题,涉及寻找数组中元素与另一数组元素差值最大值的问题,并通过二分查找找到最优解。错误的贪心策略被指出,正确的解题思路和代码展示了解题的关键——通过diff-opt_diff方式寻找最佳替换绝对值。文章强调了模运算的细节处理,确保结果的准确性。
摘要由CSDN通过智能技术生成

题目

在这里插入图片描述
oj平台

题目解析

最开始读完题,我还得意洋洋的以为,只需要找到,不改变情况下,绝对值差值最大的那个,然后对他进行差值最小的优化。。。
还是太年轻了,这样的贪心完全不对,我们将每一个绝对值差值和他的最优情况的差值进行比较,得出这两个差值的最大值,而不是单纯只考虑到原绝对值差值大。。。

  • 错误代码示范
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;
    }
};
  • 正确做法与思路:
  1. 我们通过原先的 diff-opt_diff 的方式来寻找那个最需要替换绝对值!!!
  2. 那么 opt_diff 如何求呢?可以通过二分查找找等于 nums2[i] 的左边界来寻找每个绝对值的最优解 opt_diff ,找到左边界i后,可以根据i的值分情况得到最优解.
  3. 三种情况:1.i == 0 2.i==n 3.0<i<n.这三种特殊情况都可以用两类if分流讨论:如果 i<nrec[i] - nums2[i] 一定 >=0 ,如果 i>0 ,则 nums2[i]-resc[i-1] 一定 >=0 ,这使得无论是两种特殊情况还是不特殊的情况,都将被考虑到!
  4. 关于模运算细节:模运算的分步过程中,如果出现某步使得 (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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值