差分数组的实用和简单记忆

假设 res[x] 表示的是,nums[i] + nums[n - 1 - i] 为 x 的时候,需要多少次操作。

nums[i] + nums[n - 1 - i] 的结果范围有限

我们只需要计算出所有的 x 对应的 res[x], 取最小值就好了。

极值点定边界

根据题意,nums[i] + nums[n - 1 - i] 最小是 2,即将两个数都修改为 1;最大是 2 * limit,即将两个数都修改成 limit。

所以,res[x] 中 x 的取值范围是 [2, 2 * limit]。我们用一个 res[2 * limit + 1] 的数组就好。

关键是,如何求出每一个 res[x] 位置的值,即修改后互补的数字和为 x,需要多少操作?

为了叙述方便,假设 nums[i] 为 A;nums[n - 1 - i] 为 B。

显然有:

如果修改后两个数字的和是 A + B,我们使用的操作数是 0 (没有修改));

将这个逻辑反过来会比较好理解,不操作和是A+B

否则的话,如果修改后两个数字和在 [1 + min(A, B), limit + max(A, B)] 的范围,我们使用的操作数是 1 (只需要修改 A 或者 B 就好);

将这个逻辑反过来会比较好理解,操作1次可以获得的区间是 [1 + min(A, B), limit + max(A, B)]

否则的话,如果修改后两个数字和在 [2, 2 * limit] 的范围,我们使用的操作数是 ``2`(两个数字都要修改));

所以,我们的算法是遍历每一组 nums[i] 和 nums[n - 1 - i],然后:

类似卫语句的效果

先将 [2, 2 * limit] 的范围需要的操作数 + 2;

之后,将 [1 + min(A, B), limit + max(A, B)] 的范围需要的操作数 - 1(即 2 - 1 = 1,操作 1 次);

之后,将 [A + B] 位置的值再 -1(即 1 - 1 = 0,操作 0 次)。

可以看出,整个过程都是在做区间更新。最后,我们查询每一个位置的值,取最小值就好。

对于这个需求,我们当然可以使用线段树或者树状数组解决,但代码量稍大,且复杂度也是 O(nlogn) 的。

但是仔细观察,我们发现,我们只需要作区间更新,和单点查询。

对于这个需求,有一种非常常规的”数据结构“,叫差分数组,完全满足需求,并且编程极其简单,整体可以在 O(n) 的时间解决。

简单来说,差分数组 diff[i],存储的是 res[i] - res[i - 1];而差分数组 diff[0…i] 的和,就是 res[i] 的值。

如果我们想给 [l, r] 的区间加上一个数字 a, 只需要 diff[l] += a,diff[r + 1] -= a。

这样做,diff[0…i] 的和,就是更新后 res[i] 的值。

差分数组简单理解和记忆:差分数组保存的是每两个元素之间的差值,那一直累加起来就是对应的原始数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值