Leetcode---1818绝对差值和

这篇博客介绍了如何解决一个关于数组的优化问题,即在最多替换一个元素的情况下,如何找到最小的绝对差值和。文章详细阐述了算法思路,包括先计算不替换时的绝对差值和,再利用TreeSet找到每个元素的最佳替换方案以减少差值。最终通过O(nlogn)的时间复杂度和O(2n)的空间复杂度实现解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1818绝对差值和

在这里插入图片描述

思路

拿到题首先简单分析一下:

  1. 因为nums1和nums2的长度都是n,而 1 ≤ n ≤ 1 0 5 1\le n \le 10^5 1n105,所以最多只能使用 O ( n l o g n ) O(nlogn) O(nlogn)的算法;
  2. nums1中最多只能进行一次元素替换操作,可以不进行替换。

因为求的是——进行最多一次替换后的最小绝对差值和,所以

  1. 若原本的绝对差值和就是0,那就不用进行替换了;
  2. 如果需要替换,又因为只能替换一次,那就需要找到可以最大程度减少绝对差值和的一次替换,然后在原本的绝对值和的基础上减去这一次的减少量即可;

所以得到如下的算法步骤:

  1. 首先计算不进行替换的绝对差值和ans,如果此时的ans=0,则直接返回0
  2. 否则,利用数组sub记录每一对的绝对差值
  3. 因为只能对nums1中的元素使用替代操作,所以将nums1中的元素存入TreeSet中,方便后续进行处理(有很多人使用的是二分查找来寻找合适的值,因为前几天曾经使用过TreeMap的floorKey做过题,这次使用TreeSet的floor和ceiling方法来做,但是这样的时间复杂度高了很多);
  4. 无视题目要求,可以进行无限次替换操作,使用TreeSet中的ceiling(i)和floor(i)找到nums2中当前元素对应nums1中最接近的两个元素求出nums2中每一个元素对应最佳的绝对差值,并与sub中对应的值相减,从而找到最大的减少量max
  5. 使用(ans-max+mod)%mod,然后返回即可。

因为TreeSet增删改查的时间复杂度都是 O ( l o g n ) O(logn) O(logn),再加上嵌套的循环,所以总的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
空间复杂度为 O ( 2 n ) O(2n) O(2n),其中使用sub存储元素的绝对差值、使用Treeset存储nums1的元素分别使用了 O ( n ) O(n) O(n)的空间

代码

class Solution {
    public int minAbsoluteSumDiff(int[] nums1, int[] nums2) {
        //因为n的长度为1e5所以最多只能使用nlogn的时间复杂度 n更好
        //最多只能替换一个元素
        int mod = (int) 1e9+7;
        int len = nums1.length;
        int ans = 0;

        int[] sub = new int[len];
        TreeSet<Integer> ts = new TreeSet<>();
        
        for (int i=0;i<len;i++){
            sub[i] = nums1[i]-nums2[i]>0?nums1[i]-nums2[i]:nums2[i]-nums1[i];
            ans = (ans + sub[i])%mod;
            ts.add(nums1[i]);
        }

        if (ans==0)
            return 0;
        
        int max = Integer.MIN_VALUE;
        for (int i=0;i<len;i++)
        {
            int c = ts.ceiling(nums2[i])==null?Integer.MAX_VALUE:ts.ceiling(nums2[i]);
            int f = ts.floor(nums2[i])==null?Integer.MAX_VALUE:ts.floor(nums2[i]);
            int per = Math.abs(c-nums2[i])>Math.abs(f-nums2[i])?Math.abs(f-nums2[i]):Math.abs(c-nums2[i]);
            max = Math.max(sub[i]-per,max);
        }
            

        return (ans-max + mod) % mod;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值