差分数组_LeetCode1674

差分数组是什么

  差分数组是原数组相邻两数的差值构成的数组。利用差分数组,可以快速地实现对区间内所有数同时加(减)去某个数。这是因为差分数组维护是原数组的变化量,在每次同时加(减)操作之后,除了差分数组两端的值会发生变化,差分数组内部的值保持不变。引用一位大神博客中的例子具体说明:

来源:https://note.cser.club/algorithm/untitled

原始数组和差分数组

将区间[1,4]中元素同时+3

这时我们就会发现这样一个规律,当对一个区间进行增减某个值的时候,他的差分数组对应的区间左端点的值会同步变化,而他的右端点的后一个值则会相反地变化,其实这个很好理解。


题目描述

给你一个长度为 偶数 n 的整数数组 nums 和一个整数 limit 。每一次操作,你可以将 nums 中的任何整数替换为 1 到 limit 之间的另一个整数。

如果对于所有下标 i(下标从 0 开始),nums[i] + nums[n - 1 - i] 都等于同一个数,则数组 nums 是 互补的 。例如,数组 [1,2,3,4] 是互补的,因为对于所有下标 i ,nums[i] + nums[n - 1 - i] = 5 。

返回使数组互补最少操作次数。

示例 1:

输入:nums = [1,2,4,3], limit = 4
输出:1
解释:经过 1 次操作,你可以将数组 nums 变成 [1,2,2,3]

提示:

  • n == nums.length
  • 2 <= n <= 1 0 5 10^5 105
  • 1 <= nums[i] <= limit <= 1 0 5 10^5 105
  • n 是偶数。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-moves-to-make-array-complementary


解题思路

  由已知条件可知,互补的两数之和S = nums[i]+nums[n-1-i]满足条件2 ≤ \leq S ≤ \leq 2*limit,因此只需将[2, 2*limit]中的每一个数作为互补和求出对应的操作次数,取最小值即可。

  对于每一对a = nums[i]和b = nums[n-1-i],要是它们互补,需要的操作次数可能为2、1、0。当 a+b == S时,操作次数为0;当 1+min(a,b) <= S <= limit+max(a,b)时,操作次数为1(只需换一个);当 2 <= S <= 2*limit时,操作次数为2(两个都要换)。

  通过以上分析,可以通过构造差分数组times[2*limit+2]来完成对区间的同时操作,times[i]在差分数组的原数组中表示将i当作互补和时对应的操作次数。具体算法:遍历数组nums,对于每一对a和b,

  1. 将区间[2, 2*limit]的数都+2,对应于2个操作次数,
  2. 将区间[1+min(a,b), limit+max(a,b)]的数都-1,对应于1个操作次数,
  3. 将区间[a+b, a+b]的数都-1,对应于0个操作次数,

最后将差分数组恢复成原数组,取最小值即可。算法的时间复杂度为 O ( n ) O(n) O(n)


代码

class Solution {
public:
    int minMoves(vector<int>& nums, int limit) {
        int n = nums.size(), ans = nums.size(), sum = 0;
		vector<int> times(2*limit+2);	//建立差分数组,大小2*limit+2
        for(int i = 0; i < n/2; i++){
            int a = nums[i], b = nums[n-1-i];
            //将区间[2, 2*limit]的数都+2
            times[2] += 2;
            //将区间[1+min(a,b), limit+max(a,b)]的数都-1
            times[1+min(a,b)] -= 1;
            times[1+limit+max(a,b)] += 1;
            //将区间[a+b, a+b]的数都-1
            times[a+b] -= 1;
            times[1+a+b] += 1;
        }
        //将差分数组恢复成原数组,最小值为答案
		for(int i = 2; i <= 2*limit; i++){
            sum += times[i];
            ans = min(ans, sum);
        }
        return ans;
    }
};

参考

[1] https://note.cser.club/algorithm/untitled

[2] https://leetcode-cn.com/problems/minimum-moves-to-make-array-complementary/solution/jie-zhe-ge-wen-ti-xue-xi-yi-xia-chai-fen-shu-zu-on/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值