1818. 绝对差值和

1818. 绝对差值和

前言:

这题其实挺简单的,我的简单意思是,他可以用简单粗暴的方法做,那么用这种方法做呢,肯定是要用双循环的,那么时间复杂度就是O(nn),那对于这一题的要求来说,对不起,你必定超时(别问我怎么知道,因为我试过)。
因此对于找替换元素那里的双循环,用二分查找,就可以省一点时间,时间复杂度就可以控制在:O(n
logn),这样子就不会超时啦

贴个题目:

题目

贴个示例:

运行示例


解题思路:

首先,看到题目,让我们算一个nums1[i]-nums2[i]的和,但是!有一个条件:

nums1中可以用一个元素覆盖另一个元素,但是,只能覆盖一次
而且这个覆盖能让求和的值为最小的

根据这个条件,我们明白两点:
1、只能换一次
2、而且换了之后求和为最小的

因此,我们需要nums1[j]-nums2[I]的对应每一个nums2[I]的最小值

然后由公式:

abs(nums1[i]-nums2[i])-abs(nums1[min]-nums2[i]

知道前一项abs()为定值,因此求这一个公式的最大值,就是求上述的最小值

我用一个数组maxdiff_arr存放这个公式的值

然后找出这个数组的最大值,返回其下标就是我要求的覆盖后的最小值

最后遍历nums1和nums2,一个一个加上去得到和就是正确答案了

如果这里不明白的话,尝试看一下代码,有详细注释,我可能说的不清楚


解释一下二分查找:

可以看到我的代码里面新建了一个数组cpynums1复制nums1,然后对其排序,将nums2中的元素作为目标值,找出目标值在cpynums1的插入的位置,那就可以找出那个最小值啦。

贴上代码:

int compare(const void *a,const void *b)
//qsort函数,升序排序
{
    return *(int *)a-*(int *)b;
}

int binarySearch(int *arr,int len,int target)
//二分查找:得到的是target插入的一个位置的下标,在返回值的左边,也就是我返回的是target的右边界
{
    int left=0;
    int right=len-1;
    int mid;
    while(left<right)
    {
        mid=(right-left)/2+left;
        //防止rightright+left太大越出int的范围
        if(arr[mid]<=target) left=mid+1;
        //如果target比中间值大(有可能等于中间值),这时候应该要移动左边界
        //当target等于中间值的时候,为什么要让left=mid+1呢?
        //因为我要我的返回值是右边届,因此应该跳过target==[mid]的mid值,取其右边界
        else right=mid;
        //否则就移动右边界到mid中,此时有可能是left==right,就可以返回右边界了
    }
    return left;
    //返回的是右边界的下标
}

int SearchMax(int *arr,int len)
//直接查找:nums1[i]-nums2[i])-abs(nums1[min]-nums2[i]的最大值其所对应的下标
{
    int maxnum=arr[0];
    int maxindex=0;
    for(int i=1;i<len;i++)
    {
        if(maxnum<arr[i])
        {
            maxnum=arr[i];
            maxindex=i;
        }
    }
    return maxindex;
}

const int mod=1000000007;//对结果取余mod
int minAbsoluteSumDiff(int* nums1, int nums1Size, int* nums2, int nums2Size)
{
    int cpynums1[nums1Size];
    //创建一个nums1Size的数组,准备复制nums1
    memcpy(cpynums1,nums1,nums1Size*sizeof(int));
    //复制nums1
    qsort(cpynums1,nums1Size,sizeof(int),compare);
    //将复制nums1的数组cpynums1升序排列
    int maxdiff_arr[nums1Size];
    //创建一个数组,用来存对应nums2每一个元素的abs(nums1[i]-nums2[i])-abs(nums1[min]-nums2[i]
    for(int i=0;i<nums1Size;i++)
    {
        int right_index=binarySearch(cpynums1,nums1Size,nums2[i]);
        //得到nums2[i]在cpynums1中插入位置的右边界坐标
        right_index==0?right_index=1:right_index;
        //如果右坐标为0的时候,应该让其等于1,否则下面就越界
        int min_diff=fmin(abs(nums2[i]-cpynums1[right_index]),abs(nums2[i]-cpynums1[right_index-1]));
        //这里的abs(nums1[min]-nums2[i])应该取nums2[i]与两边界的最小值
        maxdiff_arr[i]=abs(nums1[i]-nums2[i])-min_diff;
        //存进数组:abs(nums1[i]-nums2[i])-abs(nums1[min]-nums2[i])
    }
    int maxNum_index=SearchMax(maxdiff_arr,nums1Size);
    //求出abs(nums1[i]-nums2[i])-abs(nums1[min]-nums2[i])所对应的下标
    long sum=0;
    //最终的返回计算结果,别忘了取余
    for(int i = 0;i<nums1Size;i++)
    {
        if(i!=maxNum_index) sum+=abs(nums1[i]-nums2[i]);
        else sum+=abs(nums1[i]-nums2[i])-maxdiff_arr[maxNum_index];
        //如果到了所对应的下标,那就根据63行的算式:maxdiff_arr[i]=abs(nums1[i]-nums2[i])-min_diff,加上替换元素后的差值
    }
    return sum%mod;
}

性能分析:

时间复杂度:

在一个循环里面使用了二分查找,因此时间复杂度是:

O(n)*O(logn)=O(nlogn)

空间复杂度:

这题其实是用空间换时间,新建了两个数组,用来存中间值
因此空间复杂度是:

O(n)

粗暴做法(超时)

int compare(const void *a,const void *b)
{
    return *(int *)a-*(int *)b;
}


int findmaxIndex(int *array,int len)
{
    int temp=array[0];
    int maxIndex=0;
    for(int i=1;i<len;i++)
    {
        if(temp<array[i]) 
        {
            temp=array[i];
            maxIndex=i;
        }
    }
    return maxIndex;
}
const int mod=1000000007;
int minAbsoluteSumDiff(int* nums1, int nums1Size, int* nums2, int nums2Size){
    //qsort(nums1,nums1Size,sizeof(int),compare);//排序
    //qsort(nums2,nums2Size,sizeof(int),compare);//排序
    int *arr1=(int *)malloc(sizeof(int)*nums1Size);//nums1[j]-nums2[i]的最佳结果:最小值
    int *arr2=(int *)malloc(sizeof(int)*nums1Size);//存num1[i]-nums2[i] - abs(nums1[j]-nums2[i])
    for(int i=0;i<nums1Size;i++)
    {
        arr1[i]=100000;
        for(int j=0;j<nums1Size;j++)
        {
            arr1[i]=fmin(arr1[i],abs(nums1[j]-nums2[i]));
        }
        arr2[i]=abs(abs(nums1[i]-nums2[i])-arr1[i]);
    }
    int m_index=findmaxIndex(arr2,nums1Size);
    int sum=0;
    for(int i=0;i<nums1Size;i++)
    {
        if(i!=m_index) sum+=abs(nums1[i]-nums2[i]);
        else sum+=arr1[m_index];
    }
    free(arr1);
    free(arr2);
    return sum%mod;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值