大一计算机的自学总结:一维差分与等差数列差分

前言

差分和前缀和一样,也是很重要的基础算法。

一、一维差分

1.内容

当给出一个数组,每次操作让数组某个区间上的值全增加,最后要求返回整个数组的结果。若是一次一次去遍历,时间复杂度肯定很难看。差分可以做到在时间复杂度良好的情况下解决这一类问题。

注意,差分只能做到所有操作结束后返回结果,不能做到边操作边查询。

2.模板——航班预订统计

class Solution {
public:
    vector corpFlightBookings(vector>& bookings, int n) {
        vectorhelp(n+2,0);
        for(int i=0;ians(n,0);
        ans[0]=help[1];
        for(int i=1;i

 分析题意会发现这个题就是差分的模板题。

一维差分的方法就是,当操作区间为(l,r)时,在数组l位置加上要增加的数值,数组r+1位置减去要增加的数值,最后构建前缀和数组即为答案。

二、等差数列差分

1.内容

和一维差分差不多,不一样的是每次操作在区间上每个位置增加的值构成一个等差数列。

2.模板——三步必杀

#include
using namespace std;

typedef long long ll;

void solve()
{
	ll n;
	scanf("%lld",&n);
	ll m;
	scanf("%lld",&m);
	vector >kill(m,vector(4,0));
	for(ll i=0;ians(n+3,0);
	for(ll i=0,d;i

 这个基本上就是等差数列差分的模板题。

等差数列差分的方法是,每次操作在数组l位置加上等差数列的首项,在l+1位置加上公差-首项,在r+1位置减去公差+末项,在r+2位置加上末项,最后构建两次前缀和数组即可。

3.练习——Lycanthropy

#include
using namespace std;

typedef long long ll;
const ll offset=30001;

void cal(ll l,ll r,ll s,ll e,ll d,vector&help)
{
	help[l+offset]+=s;
	help[l+1+offset]+=d-s;
	help[r+1+offset]-=d+e;
	help[r+2+offset]+=e;
}

void solve()
{
	ll n;
	scanf("%lld",&n);
	ll m;
	scanf("%lld",&m);
	vector >fall(n,vector(2,0));
	for(ll i=0;ihelp(m+2*offset,0);
	for(ll i=0;i

 这个题看上去很复杂,但画个图分析一下会发现,每次落水后,左右两侧水位的变化呈等差数列,所以可以对其进行多次等差数列差分。

所有差分问题都有一个坑,就是数组下标越界的问题,所以每次准备时要准备大一点的辅助数组。而这个题又不一样,其下标可能会越界非常多,所以为了处理这个问题,考虑扩大数组大小,并最后用offset索引正确区间。

具体方法是,让答案数组的0位置对应辅助数组的offset+1位置。这里的offset为“溅起水花的最大长度”,用来处理在水池端点处落水的情况,所以在答案数组左右两侧分别加上一个offset长度。

还要注意的是,因为要求前缀和,所以不鞥只从offset+1位置开始,要从辅助数组开头开始,一直到m+offset位置。

总结

从最后一个题能看出,coding能力还要练啊!

END

你可能感兴趣的:(c++,算法,leetcode)