简介
今天在做leetcode每日一题的时候,又学到了一个特殊的数组《差分数组》。链接
差分数组的求取
对于一个正常的数组A,对于一个新建的数组B用来存储A的差分数组,那么B[i] = A[i]-A[i-1];
差分数组还有一个重要的特性:
对于差分数组B,B的前缀和就是原数组A。
用处
现在有一个数组C,想要在C上做以下操作:
- [1,5]区间内的值同时增加10;
- [2,10]区间内的值同时增加100;
当然可以使用循环遍历先让[1,5]区间内的数字增加10,然后再循环遍历让[2,10]同时增加100。在数据量比较小的时候这么做可行,如果数据量一大,需要做的操作一多,就会导致花费大量时间。
有没有办法可以在只遍历两次数组C,就可以完成操作呢?那就是使用差分数组:
- 先对C求取差分数组D。
- 想象一下,如果想要对整个C数组内的所有数字加10应该怎么做?可以在D[0]位置加10,然后对D做前缀和,那么得到的数组就是C中所有数字加10。
- 如果只想要某个区间内[i,j]的数字加10呢,可以在D[i]位置加10,然后在D[j+1]的位置再减10,这样的话得到的前缀数组其他的位置相对于C是不变的,但[i,j]区间内的数字相对于C来说都会增加10。
- 在需要操作多个区间的时候,差分数组可以有效的减少时间占用。
实例
struct IntervalAdds
{
int m_start;
int m_end;
int m_add;
IntervalAdds(int start, int end, int add) :m_start(start), m_end(end), m_add(add) {}
};
class Solution
{
public:
vector<int>IntervalAdd(const vector<IntervalAdds>& intervalAdds, const vector<int>& initialNums)
{
if (initialNums.size() <= 0)return{};
vector<int>Difference(initialNums.size(), 0);
//获取差分数组
Difference[0] = initialNums[0];
for (auto i = 1; i < initialNums.size(); ++i)
{
Difference[i] = initialNums[i] - initialNums[i - 1];
}
//区间加
for (const auto& iter : intervalAdds)
{
if (iter.m_start > iter.m_end)continue;
if (iter.m_start < Difference.size())
{
Difference[iter.m_start] += iter.m_add;
}
if (iter.m_end + 1 < Difference.size())
{
Difference[iter.m_end+1] -= iter.m_add;
}
}
//前缀和
for (auto i = 1; i < Difference.size(); ++i)
{
Difference[i] = Difference[i] + Difference[i - 1];
}
return Difference;
}
};
Solution sl;
vector<IntervalAdds> adds{ {0, 2, 10},{3, 10, 20}, {5, 9, 8} };
vector<int>sorce(20, 0);
auto res = sl.IntervalAdd(adds, sorce);
for (auto i : res)cout << i << " ";
输出: