青训营 差分数组一般解法 特例题解 | 豆包MarsCode AI刷题
案例引入
有时候我们遇到需要频繁对数组中某个区间进行加减操作,此时如果正常遍历则会导致时间复杂度增加,而通过差分数组能极大优化这一过程。今日刷题中遇到一道名为打点计数器的区间合并题,通过差分数组能很快求解。本题使用go语言进行解答。
题目描述:
题目初步分析:
在本题中,小明需要计算在给定区间打点后,整个范围内一共有多少点。考虑到本题需要频繁对某个区间修改,因此采用差分数组进行求解:先遍历inputArray来更新差分数组状态,再遍历差分数组得到答案。
题目详解:
-
首先初始化所需要设立差分数组,由于本题没有明确整个数字范围大小,因此考虑先设置一个长度较大的数组,再根据所给出inputArray中数字的最小值与最大值来对数组进行切片处理。这样便能满足最后遍历时只需要遍历所需范围。
cnt := make([]int, 100000001)//设置较大长度的数组 mx := math.MinInt//初始化最大值 mn := math.MaxInt//初始化最小值 -
遍历inputArray来对差分数组进行更新:
将区间起点值加1,区间终点后一位减1。这样能够保证在遍历差分数组时所得索引值在区间内为1区间外为零。同时每次都判断左边界、右边界与当前最小值最大值,以维护整个区间范围。在遍历inputArray接受根据最大值与最小值来进行切片操作。
for _, v := range inputArray { cnt[v[0]]++//左边界加一 cnt[v[1]+1]--//右边界减一 if v[1] > mx { mx = v[1] + 1//更新最大值 } if v[0] < mn { mn = v[0]//更新最小值 } } cnt = cnt[mn:mx]//进行切片操作 -
遍历差分数组得到结果:
在遍历时,当前索引的值更新为前一个索引的值加上当前索引值,如果大于零则说明当前索引被打过点,打点数加一。最终返回打点数则为结果。
num := 1//区间最左边一定打点 for i := 1; i < len(cnt); i++ { cnt[i] += cnt[i-1] if cnt[i] > 0 { num++ }//如果更新后值大于零则说明被打点 }
完整代码如下:
func solution(inputArray [][]int) int {
// Please write your code here
cnt := make([]int, 100000001)
mx := math.MinInt
mn := math.MaxInt
for _, v := range inputArray {
cnt[v[0]]++
cnt[v[1]+1]--
if v[1] > mx {
mx = v[1] + 1
}
if v[0] < mn {
mn = v[0]
}
}
num := 1
cnt = cnt[mn:mx]
for i := 1; i < len(cnt); i++ {
cnt[i] += cnt[i-1]
if cnt[i] > 0 {
num++
}
}
return num
}
运行结果如下:
差分数组一般解法:
在解答完本题后,运用豆包AI对差分数组的一般解法进行归纳:
差分数组的基本概念
假设我们有一个原始数组 arr,长度为 n。我们可以构建一个差分数组 diff,其中 diff[i] 表示 arr[i] 和 arr[i-1] 之间的差值。具体来说:
diff[0] = arr[0]diff[i] = arr[i] - arr[i-1]对于i > 0
差分数组的应用
差分数组主要用于以下两种操作:
- 区间更新:对数组
arr的某个区间[l, r]进行加减操作。 - 查询单点值:通过差分数组还原出原始数组
arr中的某个位置的值。
区间更新操作
假设我们要对数组 arr 的区间 [l, r] 进行加 k 的操作。我们可以通过以下步骤在差分数组 diff 中进行更新:
diff[l] += kdiff[r+1] -= k(如果r+1在数组范围内)
查询单点值
通过差分数组 diff,我们可以还原出原始数组 arr 中的某个位置的值。具体来说:
arr[i] = diff[0] + diff[1] + ... + diff[i]
总结与思考
本题难度较低,适合作为差分数组算法的入门题进行解答。在使用差分数组时需要考虑左右边界是否取闭区间,且需要明确需要遍历的范围来减少额外消耗。