读完本文,你不仅学会了算法套路,还可以顺便去 LeetCode 上拿下如下题目:
http://ww1.sinaimg.cn/large/9b63ed6fgy1glvqyy7v1qj20xc0m8wgt.jpg
前文 前缀和技巧详解 写过的前缀和技巧是非常常用的算法技巧,前缀和主要适用的场景是原始数组不会被修改的情况下,频繁查询某个区间的累加和。
没看过前文没关系,这里简单介绍一下前缀和,核心代码就是下面这段:
class PrefixSum {
// 前缀和数组
private int[] prefix;
/* 输入一个数组,构造前缀和 */
public PrefixSum(int[] nums) {
prefix = new int[nums.length + 1];
// 计算 nums 的累加和
for (int i = 1; i < prefix.length; i++) {
prefix[i] = prefix[i - 1] + nums[i - 1];
}
}
/* 查询闭区间 [i, j] 的累加和 */
public int query(int i, int j) {
return prefix[j + 1] - prefix[i];
}
}
prefix[i]
就代表着 nums[0..i-1]
所有元素的累加和,如果我们想求区间 nums[i..j]
的累加和,只要计算 prefix[j+1] - prefix[i]
即可,而不需要遍历整个区间求和。
本文讲一个和前缀和思想非常类似的算法技巧「差分数组」,差分数组的主要适用场景是频繁对原始数组的某个区间的元素进行增减。
比如说,我给你输入一个数组 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
即可:
题目描述
知识点
查分数组
我的实现
结果
码前思考
- 利用差分数组进行解题,
diff[i] = num[i] - num[i-1]
;
代码实现
//使用差分数组解题
//diff[i] = num[i]-num[i-1]
class Solution {
public:
vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
vector<int> diff(n+2,0);
int len = bookings.size();
for(int idx=0;idx<len;idx++){
int i = bookings[idx][0];
int j = bookings[idx][1];
int k = bookings[idx][2];
diff[i] = diff[i]+k;
diff[j+1] = diff[j+1]-k;
}
vector<int> res;
res.push_back(diff[1]);
for(int i=2;i<=n;i++){
res.push_back(res[i-2]+diff[i]);
}
return res;
}
};
码后反思
- 写代码的时候有点不清醒,把数组下标写错了;
- 对于这道题,还有一个类似的题目是上下车问题,此时
[i,j,k]
表示有k
个人从i
站坐到j+1
站下车,求解每一站有多少人。 - 从今天开始每日一题了,不然研究生毕业可找不到工作的呢~