当我们需要频繁的对数组nums的某个区间 [i, j] 元素进行加减操作时,按照常规的思路,我们都是直接使用for循环暴力进行加减
//例如对数组元素加上k
func Increment(nums []int, k int) []int {
for i := range nums {
nums[i] += k
}
return nums
}
通过for循环进行增减次数少的操作时,还可以适用。但是当要频繁的对某个区间进行增减操作时,时间复杂度就会剧增,假设需增减M次,由于每次增减操作平均时间复杂度要去到O(N),最终就会导致整体时间复杂度去到O(M*N)。
差分数组
定义: 查分数组是一个与原数组具有相等长度的数组,其第i个位置的值,表示原数组中第i个位置的值减去原数组第i-1位置的值。即:
//建立差分数组
diff[0] = nums[0] //i==0
diff[i] = nums[i] - nums[i-1] //i>0
//根据差分数组还原原数组
nums[0] = diff[0] //当i==0
nums[i] = diff[i] + nums[i-1] //i>0
比如我们现在有个数组nums={0,2,5,4,9,7,10,0}
根据规则我们建立差分数组:
diff[i]= nums[i] - nums[i-1] (i>0)
现在我们在一个区间[1,4]上进行修改,给区间上的数加上3
通过差分数组,我们只需要给1位置上的数加上3,中间位置数不动,给4+1位置上的数减3,就完成了所有操作,时间复杂度为O(1)。
解释:当我们还原到原数组时,由于nums[i] = diff[i] + nums[i-1],我们给1号位置加上3后,2、3、4、5位置都会同时加上3,但是我们区间是到4,所以在5号位置上要减3来保持一致
该方法适用于区间频繁修改,而且这个区间范围是比较大的情况,我们可以将给差分数组绑定方法便于使用
type Diff struct {
diff []int
}
func (d *Diff) CreateDiff(nums []int) []int {
diff := make([]int, len(nums))
diff[0] = nums[0]
for i := 1; i < len(nums); i++ {
diff[i] = nums[i] - nums[i-1]
}
d.diff = diff
return d.diff
}
//加减操作
func (d *Diff) Operate(i, j int, value int) {
d.diff[i] += value
d.diff[j+1] -= value
}
//返回操作后的原数组
func (d *Diff) Result() []int {
nums := make([]int, len(d.diff))
nums[0] = d.diff[0]
for i := 1; i < len(d.diff); i++ {
nums[i] = d.diff[i] + nums[i-1]
}
return nums
}