差分数组
差分数组
前言:
有的时候我们需要对一个数组范围进行多次批量操作,在数组长度很小的时候,直接遍历数组进行操作就可以了。但是当数组长度很大的时候,批量操作很多次效率就会很低,有没有什么快速的方式可以完成这样的操作呢?就是今天要讲到的差分数组了,可以只操作少量的元素来完成批量操作。
介绍
差分数组是在原来的数组上进行用两两作差构造出来一个长度一样的数组(当前的元素减去前面的元素),叫做差分数组,后续操作就可以在差分数组上完成。
原数组:[ai…an]
差分数组:[a(i), a(i+1) - a(i), a(i+2) - a(i+1)….a(n)- a(n-1)]
diff[i] = \left { arr[0], i = 0 \ arr[i] - arr[i-1], i >=1 \right }
差分数组的性质:
性质1:diff[]从左往右累加a[i] = d[i-1] + d[i],可以得到原数组。
性质2:原数组区间累加/减(a[i],a[i+1]…a[j])等于差分数组 d[i] + x并且d[j+1] - x。
特殊情况: j + 1 = 数组长度 , 不需要d[j + 1] - x了,只要d[i] + x。
举个例子:
原数组: [1,0,2,6,7,3]
差分数组:[1,-1,2,4,1,-4]
如果我们要给原数组0-3都加上1,就会变成[1,1,3,7,8,4],我们操作差分数组就只需要将-1加上1就可以了,差分数组变成[1,0,2,4,1,-1],然后把差分数组从左到右累加,就变成了[1,1,3,7,8,4]。这样如果是很长的一个数组频繁的累加/减操作,我们都只需要操作两个元素就行了,最后在从左往右累加就可以得出原来数组的结果。
差分数组的典型使用场景:
频繁的区间增加/减少操作
例如给数组A的[i,j]区间中的每个元素加上c,只需要B[i] += c, B[j+1] -= c
找到数组的区间和
例如求A数组[i,j]区间元素的和,只需要计算sum(B[i]…B[j])。
解决子数组最大子段和问题
构造差分数组,其前缀和即为原数组的最大段和
- 解决数组元素出现频率问题
记录差分数组的前缀和,即为原数组中元素出现的频次
总体来说,差分数组适用于需要频繁操作数组区间的场景,可以高效减少操作次数。
实例
LeetCode-2772,这个也是353周赛的第四题。
1 | 2772. 使数组中的所有元素都等于零 |
这一题可以用差分数组来解决,首先要能满足最后元素全部为0,那么不管是原数组还是差分数组第一个元素肯定是0。
如果nums[0] > 0, nums[0]- nums[k]范围的元素都是需要减1来慢慢达成为0的条件, 依次遍历下去
前提是k < n , 要不然不满足题目要求,如果当前元素是i, 那就是i + k < n。
如果nums[0] = 0, 那么就不用管第一个数了,跳过去看下一个数
如果nums[0] < 0, 那肯定没法继续了,不可能达到都为0的情况了
遍历的时候记录一下差分的值sumDiff,最后nums[i] + sumDiff就是实际值
1 | public boolean checkArray(int[] nums, int k) { |
相关题目
题号 | 题目 | 难度 |
---|---|---|
729 | 我的日程安排表 I | 中等 |
1109 | 航班预订统计 | 中等 |
1094 | 拼车 | 中等 |
2406 | 将区间分为最少组数 | 中等 |
2528 | 最大化城市的最小供电站数目 | 困难 |