首先差分主要是针对一个数组中的元素进行频繁的增加或删除。假设现在有一个数组nums,现在我要对里面的某个区间的元素全部加2,
然后要对另外一个区间全部减1。一般的思路是直接for循环进行遍历,这样的话时间复杂度是O(n),而我们使用差分数组的话时间复杂度为O(1)。
对于一个数组nums,它的差分数组diff_array的定义为
if( i == 0 ) diff_array[0] = nums[0];
if( i > 0 ) diff_array[i] = nums[i] - nums[i - 1]
也就是说我们对nums数组中的相邻元素进行两两做差(用右边减去左边),然后再在开头补上一个nums[0]就得到了它的差分数组。
举个例子:
nums = [1,5,6,8,9],那么按照上述操作相减之后的数组就是 diff_array[4,1,2,3],最后我们将nums[0]补在开头,得到最终的差分数组
diff_array[1,4,1,2,1]。这里我们可以用到差分数组的第一个性质:从左到右累加 diff_array 中的元素,可以得到数组 nums。(建议自己试一下)
现在我们如果要将nums[1]到nums[3]的元素全部加上5,得到nums1
nums1[1,10,11,13,9]。现在对这个数组进行差分,得到的数组
diff_array1[1,9,1,2,-4]。我们将两个差分数组进行对比,发现只有diff_arrary[1]和diff_arrary[4]改变了,而在上面我们提到了可以通过差分数组还原
为原来的数组,那是不是就说明,我们只需要更改差分数组中的元素,就能够对原数组的一个区间的值进行修改。
通过对比我们发现diff_array[1] += 5得到了diff_arry1[1],而diff_arry[4] -= 5得到了diff_arry1[4]
这里我们得到了第二个性质:对原数组nums的区间 i 到 j 都增加一个数 x 等于 对差分数组diff_array中的diff_array[i] += x,diff_array[j+1] -= x。
那如果是减小x呢?很简单只需要交换一下符号既可。
https://leetcode.cn/problems/range-addition/description/
题目如下:
假设你有一个长度为 n 的数组,初始情况下所有的数字均为 0,你将会被给出 k 个更新的操作。
其中,每个操作会被表示为一个三元组:[startIndex, endIndex, inc],你需要将子数组 A[startIndex ... endIndex](包括 startIndex 和 endIndex)增加 inc。
请你返回 k 次操作后的数组。
样例
- 输入: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]]
- 输出: [-2,0,3,5,3]
-
- 初始状态:[0,0,0,0,0]
- 进行了操作 [1,3,2] 后的状态:[0,2,2,2,0]
-
- 进行了操作 [2,4,3] 后的状态:[0,2,5,5,3]
-
- 进行了操作 [0,2,-2] 后的状态:[-2,0,3,5,3]
思路:该题就是直接考察的差分数组,给出了要修改区间的起点,终点,以及要修改的值。
代码实现:
- class Solution
- {
- public:
- std::vector<int> getModifiedArray(int length, std::vector<std::vector<int>> &updates)
- {
- //定义一个ans用于记录结果,diff_array用作差分数组
- std::vector<int>ans(length,0);
- std::vector<int> diff_array(length+10);
- //让diff_array[0] = ans[0]就表示我们将ans[0],补在了差分数组的开头
- diff_array[0] = ans[0];
- //第一步先求一下差分数组,这题其实可以不写,因为初始的数组全是0
- for (int i = 1; i < length;i++)
- diff_array[i] = ans[i] - ans[i - 1];
-
- //第二步进行数组的修改
- for (int i = 0; i < updates.size();i++){
- //updata[i][0]代表修改的起点,updata[i][1] + 1代表要修改的终点,updata[i][2]代表要修改的值
- diff_array[updates[i][0]] += updates[i][2];
- diff_array[updates[i][1] + 1] -= updates[i][2];
- }
-
- //第三步,通过差分数组还原初始数组
- ans[0] = diff_array[0];
- for (int i = 1; i < length;i++){
- ans[i] += diff_array[i] + ans[i - 1];
- }
- return ans;
- }
- };
题目如下:
车上最初有 capacity 个空座位。车 只能 向一个方向行驶(也就是说,不允许掉头或改变方向)
给定整数 capacity 和一个数组 trips , trip[i] = [numPassengersi, fromi, toi] 表示第 i 次旅行有 numPassengersi 乘客,接他们和放他们的位置分别是 fromi 和 toi 。这些位置是从汽车的初始位置向东的公里数。
当且仅当你可以在所有给定的行程中接送所有乘客时,返回 true,否则请返回 false。
输入:trips = [[2,1,5],[3,3,7]], capacity = 4 输出:false
输入:trips = [[2,1,5],[3,3,7]], capacity = 5 输出:true
思路:对于该题而言,我们用number[i]表示到i这个地方时车上的人数是多少,如果大于capacity就代表着超载了。题目中的trips[i]就表示我们从
fromi 到 toi 增加了numPassengersi个人。就等于增加区间的值,可以使用差分数组
代码实现:
- class Solution
- {
- public:
- bool carPooling(std::vector<std::vector<int>> &trips, int capacity)
- {
- //第一步创建一个差分数组
- int n = trips.size();
- std::vector<int> v(1010);
-
- //第二步进行差分
- for (int i = 0; i < n; i++){
- v[trips[i][1]] += trips[i][0];
- v[trips[i][2]] -= trips[i][0];
- }
-
- //第三步,进行还原,这里还原出来的是到达i时车上的人数。
- int sum = 0;
- for(int number:v){
- sum += number;
- //在还原的时候我们判断sum是否会超过capacity的
- if(sum > capacity)
- return false;
- }
- return true;
- }
-
- };