本文讲一个和前缀和思想非常类似的算法技巧「差分数组」,差分数组的主要适用场景是频繁对原始数组的某个区间的元素进行增减。
比如说,我给你输入一个数组 nums
,然后又要求给区间 nums[2..6]
全部加 1,再给 nums[3..9]
全部减 3,再给 nums[0..4]
全部加 2,再给...
一通操作猛如虎,然后问你,最后 nums
数组的值是什么?
常规的思路很容易,你让我给区间 nums[i..j]
加上 val
,那我就一个 for 循环给它们都加上呗,还能咋样?这种思路的时间复杂度是 O(N),由于这个场景下对 nums
的修改非常频繁,所以效率会很低下。
这里就需要差分数组的技巧,类似前缀和技巧构造的 prefix
数组,我们先对 nums
数组构造一个 diff
差分数组,diff[i]
就是 nums[i]
和 nums[i-1]
之差:
int[] diff = new int[nums.length]; // 构造差分数组 diff[0] = nums[0]; for (int i = 1; i < nums.length; i++) { diff[i] = nums[i] - nums[i - 1]; }
通过这个 diff
差分数组是可以反推出原始数组 nums
的,代码逻辑如下:
int[] res = new int[diff.length]; // 根据差分数组构造结果数组 res[0] = diff[0]; for (int i = 1; i < diff.length; i++) { res[i] = res[i - 1] + diff[i]; }
这样构造差分数组 diff
,就可以快速进行区间增减的操作,如果你想对区间 nums[i..j]
的元素全部加 3,那么只需要让 diff[i] += 3
,然后再让 diff[j+1] -= 3
即可:
这里有 n 个航班,它们分别从 1 到 n 进行编号。
我们这儿有一份航班预订表,表中第 i 条预订记录 bookings[i] = [i, j, k] 意味着我们在从 i 到 j 的每个航班上预订了 k 个座位。
请你返回一个长度为 n 的数组 answer,按航班编号顺序返回每个航班上预订的座位数。
示例:
输入:bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
输出:[10,55,45,25,25]
提示:
1 <= bookings.length <= 20000
1 <= bookings[i][0] <= bookings[i][1] <= n <= 20000
1 <= bookings[i][2] <= 10000
class Solution { public: vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) { //引入差分数组:结果数组全0,差分数组全为0 vector<int> ans(n,0); vector<int> diff(n,0); //每次变化,在差分数组i开始加,j+1处减 // 0 1 10 (10 0 -10 0 0) // 1 2 20 // 1 4 25 int row = bookings.size(); for(int i=0;i<row;i++){ int start = bookings[i][0]-1; int end = bookings[i][1]-1; if(start >=0) diff[start]+=bookings[i][2]; if(end < n-1) diff[end+1]-=bookings[i][2]; } ans[0] = diff[0]; for(int i=1;i<n;i++){ ans[i] = ans[i-1]+diff[i]; } return ans; } };