- 差分数组是一种用于高效处理数据序列上一段区间内每个元素增减同一个值的技术。它常用于数组和列表数据结构中,可以让区间修改的操作时间复杂度降低到O(1),查询操作的时间复杂度为O(n)。
差分数组
差分数组是一种用于高效处理数据序列上一段区间内每个元素增减同一个值的技术。它常用于数组和列表数据结构中,可以让区间修改的操作时间复杂度降低到O(1),查询操作的时间复杂度为O(n)。 差分数组技巧适用场合:频繁对数组的某个区间的元素进行增减。
假设有一个初始数组
arr
,长度为 n。**差分数组diff
定义为每个位置上的元素与前一个元素的差值,即diff[i] = arr[i] - arr[i-1]
**,在给区间增加或减小某个数时,我们始终只维护差分数组。为了方便处理,我们通常令diff[0] = arr[0]
。再直观地说,
diff[i]
就表示arr[i]
比arr[i-1]
大多少(可以是负数),所以根据arr[i-1] + diff[i]
就可以得到arr[i]
。我们总是维护一个和数组arr
相关的diff
,并且diff[0]
一直与arr[0]
相等,因此任意时刻可以复原arr
数组。- 给定数组
arr
,构建差分数组diff
的过程如下:- 初始化
diff[0] = arr[0]
。 - 对于
arr
中的每个元素arr[i]
( i 从 1 开始),令diff[i] = arr[i] - arr[i-1]
。
- 初始化
- 给定数组
那么差分数组有什么用呢?有以下两种常见的场景:
区间修改:如果要将
arr
中从l
到r
(包括两端点)的所有元素都加上一个值v
,我们只需要对差分数组做两步操作:- **
diff[l] += v
**,这意味着arr
中的元素从位置l
开始,每个元素都增加了 v。(注意这里只是对diff[l]
加了一个 v) - **如果
r + 1 < n
,则diff[r + 1] -= v
**,这意味着从位置r + 1
开始,arr 的每个元素应该恢复原来的值,不再增加v。
举个例子,对数组
arr = {1, 2, 3, 4}
,其差分数组为diff = {1, 1, 1, 1}
。如果要对[1,2]
区间内的数字加 10,则将diff
数组的值更新为diff = {1, 11, 1, -9}
即可。可以看到,只对diff[1]
和diff[3]
的数据进行了修改。- 通过上述操作,我们在 O(1) 时间内完成了区间修改。
- **
查询操作:要恢复
arr
中的某个元素值,或者得到修改后的数组,我们只需要对差分数组diff
做前缀和操作。具体来说,arr[i] = diff[0] + diff[1] + ... + diff[i]
。值得注意的是:diff[0]
永远保持着真实的arr[0]
的值。
差分数组最大的优势在于能够非常高效地对原始数组的连续区间进行增减操作。在处理大量区间增减值的问题时,差分数组能够大幅度减少计算量,尤其是在数据量大、修改操作频繁的情况下。
1.航班预订统计
题目
这里有
n
个航班,它们分别从1
到n
进行编号。有一份航班预订表
bookings
,表中第i
条预订记录bookings[i] = [firsti, lasti, seatsi]
意味着在从firsti
到lasti
(包含firsti
和lasti
)的 每个航班 上预订了seatsi
个座位。请你返回一个长度为
n
的数组answer
,里面的元素是每个航班预定的座位总数。示例 1:
1
2
3
4
5
6
7
8
9输入:bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
输出:[10,55,45,25,25]
解释:
航班编号 1 2 3 4 5
预订记录 1 : 10 10
预订记录 2 : 20 20
预订记录 3 : 25 25 25 25
总座位数: 10 55 45 25 25
因此,answer = [10,55,45,25,25]示例 2:
1
2
3
4
5
6
7
8输入:bookings = [[1,2,10],[2,2,15]], n = 2
输出:[10,25]
解释:
航班编号 1 2
预订记录 1 : 10 10
预订记录 2 : 15
总座位数: 10 25
因此,answer = [10,25]提示:
1 <= n <= 2 * 104
1 <= bookings.length <= 2 * 104
bookings[i].length == 3
1 <= firsti <= lasti <= n
1 <= seatsi <= 104
思路
因为是频繁对区间的修改,所以可以考虑使用差分数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class Solution {
public int[] corpFlightBookings(int[][] bookings, int n) {
int[] answer = new int[n];
int[] diff = new int[n];
// 差分数组第一项:diff[0] = arr[0]
diff[0] = 0;
for (int i = 0; i < bookings.length; i++) {
// 因为航班从1开始编号,所以要-1
int first = bookings[i][0] - 1;
int last = bookings[i][1] - 1;
int seats = bookings[i][2];
// 使用差分数组的思想
diff[first] += seats;
if (last + 1 < n) {
diff[last + 1] -= seats;
}
}
// 最后由差分数组得到结果
answer[0] = diff[0];
for (int i = 1; i < n; i++) {
answer[i] = answer[i - 1] + diff[i];
}
return answer;
}
}