2025年3月21日 星期五 甲辰(龙)年 月廿 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > Other

差分数组

时间:02-25来源:作者:点击数:9

一、差分定义和性质

首先差分主要是针对一个数组中的元素进行频繁的增加或删除。假设现在有一个数组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呢?很简单只需要交换一下符号既可。

二、差分数组的运用

1.力扣370(区间加法)

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;
  • }
  • };

2.力扣1094(拼车)

题目如下:

车上最初有 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;
  • }
  • };
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐