【有营养的算法笔记】基础算法 —— 推导证明前缀和与差分_前缀和 证明(3)

所以,我们发现,前缀和多开了一个数组,以达到优化计算时间的效果,是典型的 以空间换时间 的算法。

2、代码实现

接下来做道前缀和例题练练手。

链接795. 前缀和

描述

输入一个长度为

n

n

n 的整数序列。

接下来再输入

m

m

m 个询问,每个询问输入一对

l

,

r

l, r

l,r。

对于每个询问,输出原序列中从第

l

l

l 个数到第

r

r

r 个数的和。

输入格式

第一行包含两个整数

n

n

n 和

m

m

m 。

第二行包含

n

n

n 个整数,表示整数数列。

接下来

m

m

m 行,每行包含两个整数

l

l

l 和

r

r

r ,表示一个询问的区间范围。

输出格式

m

m

m 行,每行输出一个询问的结果。

数据范围

  • 1

l

r

n

1≤l≤r≤n

1≤l≤r≤n

  • 1

n

,

m

100000

1≤n,m≤100000

1≤n,m≤100000

1000

数列中元素的值

1000

−1000 ≤ 数列中元素的值 ≤ 1000

−1000≤数列中元素的值≤1000

输入样例:

5 3
2 1 3 6 4
1 2
1 3
2 4

输出样例:

3
6
10

思路 :典型的前缀和例题,思路我们上面已经讲过一遍了,直接开始写代码:

image-20221223072816069

二、二维前缀和

二维前缀和是一维前缀和的加强。

从前只能求一维序列的前缀和,现在能求二维,也就是矩阵的前缀和。

1、算法推导

接下来看 二维前缀和数组 是如何构造的:

image-20221223075655178

假设给定二维矩阵

a

s

a 和 s

a和s ,

s

s

s 为前缀和矩阵,这里我们设定一个前提:竖直方向我们统一称为长,横平的边我们统一称为宽,以便我们描述图形。

假如要求 **点

(

i

,

j

)

(i, j)

(i,j)** 的前缀和,那么对于图中,以

i

,

j

i, j

i,j 为长和宽的矩阵就是 点

(

i

,

j

)

(i, j)

(i,j) 的前缀和。

观察上图,可以得到面积公式:

一整块矩形面积

=

紫色面积

绿色面积

蓝色面积

红色面积

一整块矩形面积 = 紫色面积 + 绿色面积 + 蓝色面积 + 红色面积

一整块矩形面积=紫色面积+绿色面积+蓝色面积+红色面积
但是,对于矩阵的面积,有些地方是无法单独计算的,比如绿色区域,只能算以

i

1

i - 1

i−1 为长,

j

j

j 为高的面积。

所以,我们实际计算时,真正的计算公式 为:

一整块矩形面积

=

i

1

为长以

j

为高的矩形面积

i

为长以

j

1

为高的矩形面积

紫色面积

红色面积

一整块矩形面积 = 以\ i - 1 \ 为长以 \ j \ 为高的矩形面积 + 以\ i \ 为长以 \ j - 1 \ 为高的矩形面积 - 紫色面积 \ + \ 红色面积

一整块矩形面积=以 i−1 为长以 j 为高的矩形面积+以 i 为长以 j−1 为高的矩形面积−紫色面积 + 红色面积
以图表示:

image-20221223083202107

至于为什么要加 紫色区域 呢?这是因为在加绿色矩阵和蓝色矩阵的时候,加了两次 紫色区域 ,所以需要去掉重复的这一块。

而这里的每一个与长和宽有直接关联的区域其实就是这一块区域的 前缀和 ,在

s

s

s 矩阵中都可以表示出来,而 红色小方格的面积 则是

a

a

a 矩阵当前位置的元素,所以我们可以得到 二维矩阵前缀和预处理公式

s

[

i

]

[

j

]

=

s

[

i

1

]

[

j

]

s

[

i

]

[

j

1

]

s

[

i

1

]

[

j

1

]

a

[

i

]

[

j

]

s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]

s[i][j]=s[i−1][j]+s[i][j−1]−s[i−1][j−1]+a[i][j]
那么我们构造过程的代码也就可以写出来了:

for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
        }
    }

而对于二维前缀和,我们的题型通常是求 子矩阵的和 ,比如:

image-20221223085415915

以我们平常的思维方式,就是 两层循环遍历一下 ,时间复杂度为

O

(

N

×

M

)

O(N \times M)

O(N×M)。

但是如果我们使用 前缀和 呢?实际上只需要

O

(

1

)

O(1)

O(1) 的时间复杂度,是非常快的,但是前提得有公式,所以我们得先把公式推导出来。

推导过程

我们再进行严格的区域划分,画一张较为详细的图:

同样的这里设定前提:竖直方向的边统一称为长,横平方向的边统一称为宽,以便我们描述图形。

image-20221223090802848

根据上图,我们可以得出公式:

蓝色面积

=

x

2

为长,

y

2

为宽的区域面积

黄色面积

绿色面积

紫色面积

蓝色面积 = 以 \ x2 \ 为长,\ y2 \ 为宽的区域面积 - 黄色面积 - 绿色面积 - 紫色面积

蓝色面积=以 x2 为长, y2 为宽的区域面积−黄色面积−绿色面积−紫色面积
但是这里的区域面积也是不好算一小块的,区域的面积的长和宽要从

(

1

,

1

)

(1, 1)

(1,1) 出发,所以我们 真正的公式 为:

蓝色面积

=

x

2

为长

y

2

为宽的区域面积

x

1

1

为长

y

2

为宽的区域面积

x

2

为长

y

1

1

为宽的区域面积

紫色面积

蓝色面积 = 以 \ x2 \ 为长 \ y2 \ 为宽的区域面积 - 以 \ x1 - 1 为长\ y2 \ 为宽的区域面积 - 以 \ x2 \ 为长 \ y1 - 1 \ 为宽的区域面积 + 紫色面积

蓝色面积=以 x2 为长 y2 为宽的区域面积−以 x1−1为长 y2 为宽的区域面积−以 x2 为长 y1−1 为宽的区域面积+紫色面积
加上 紫色面积 的原因是,我们减去了两块 紫色面积 ,需要补上一个。

同样的,这里每块区域的面积,实际上就是 前缀和 ,比如 紫色面积就是

a

a

a 矩阵中以

x

1

1

x1- 1

x1−1 为长,

y

1

1

y1 - 1

y1−1 的区域面积,前缀和形式就直接为

s

[

x

1

1

]

[

y

1

1

]

s[x1 -1][y1 - 1]

s[x1−1][y1−1]。

所以这里写出我们的 查询公式

蓝色面积

=

s

[

x

2

]

[

y

2

]

s

[

x

1

1

]

[

y

2

]

s

[

x

2

]

[

y

1

1

]

s

[

x

1

1

]

[

y

1

1

]

蓝色面积 = s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]

蓝色面积=s[x2][y2]−s[x1−1][y2]−s[x2][y1−1]+s[x1−1][y1−1]
到这里,我们的前缀和的核心公式都已经推导出来了,在做题目是就很方便了,只需要:预处理 + 查询

2、代码实现

链接796. 子矩阵的和

描述

输入一个

n

n

n 行

m

m

m 列的整数矩阵,再输入

q

q

q 个询问,每个询问包含四个整数

x

1

,

y

1

,

x

2

,

y

2

x1,y1,x2,y2

x1,y1,x2,y2,表示一个子矩阵的左上角坐标和右下角坐标。

对于每个询问输出子矩阵中所有数的和。

输入格式

第一行包含三个整数

n

n

n,

m

m

m,

q

q

q 。

接下来

n

n

n 行,每行包含

m

m

m 个整数,表示整数矩阵。

接下来

q

q

q 行,每行包含四个整数

x

1

,

y

1

,

x

2

,

y

2

x1,y1,x2,y2

x1,y1,x2,y2 ,表示一组询问。

输出格式:

q

q

q 行,每行输出一个询问的结果。

数据范围:

  • 1

n

,

m

1000

1≤n,m≤1000

1≤n,m≤1000

  • 1

q

200000

1≤q≤200000

1≤q≤200000

  • 1

x

1

x

2

n

1≤x1≤x2≤n

1≤x1≤x2≤n

  • 1

y

1

y

2

m

1≤y1≤y2≤m

1≤y1≤y2≤m

1000

矩阵内元素的值

1000

−1000≤矩阵内元素的值≤1000

−1000≤矩阵内元素的值≤1000

输入样例

3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4

输出样例

17
27
21

思路

上面公式我们推导过了,直接预处理 + 查询即可:

image-20221223094216405

三、一维差分

其实博主觉得差分是一个很抽象的算法,我们可以构造差分数组算,同样的也可以通过另一种方式不构造数组求出结果。

至于为什么我会这么觉得,别急,我们慢慢来,先讲差分的思想再说~

1、算法推导

前面我们学了前缀和,现在又要学差分,它们之间有联系吗?

实际上可以简单推测一下,一个是求 ”和“ ,一个是求 ”差“ ,那 差分是不是就是前缀和的逆运算 ?答案是正确的,差分其实就是前缀和的一个反推。

对于差分算法我们一般得先 构造差分数组 ,假设现在有两个数组

a

b

a 和\ b

a和 b :

我们需要构造

b

b

b 为差分数组,**使得

a

a

a 数组是

b

b

b 的前缀和数组** ,也就是说

a

a

a 中每一个数据,都是

b

b

b 中在包括这个位置之前所有的数据的和。这时

b

b

b 被称为

a

a

a 的差分。

**所以

b

b

b 数组每个元素无非就是

a

a

a 数组的每一个元素与其前一个元素的差嘛!**

为什么这么说?我们来算一下就知道了:

a

[

i

]

=

b

[

1

]

b

[

2

]

.

.

.

b

[

i

]

a

[

i

1

]

=

b

[

1

]

b

[

2

]

.

.

.

b

[

i

1

]

a

[

i

]

a

[

i

1

]

=

(

b

[

i

]

b

[

i

1

]

.

.

.

b

[

2

]

b

[

1

]

)

(

b

[

i

1

]

.

.

.

b

[

2

]

b

[

1

]

)

=

b

[

i

]

\begin{align} & a[i] \ \ \ \ \ \ \ = b[1] + b[2] + … + b[i] \newline \newline & a[i - 1] = b[1] + b[2] + … + b[i - 1] \newline \newline & a[i] - a[i - 1] = ({\color{red}b[i]} + b[i - 1] + … + b[2] + b[1]) - (b[i - 1] + … + b[2] + b[1]) = {\color{red}b[i]} \end{align}

​a[i]       =b[1]+b[2]+…+b[i]a[i−1]=b[1]+b[2]+…+b[i−1]a[i]−a[i−1]=(b[i]+b[i−1]+…+b[2]+b[1])−(b[i−1]+…+b[2]+b[1])=b[i]​​
所以 **差分数组

b

b

b 的构造方式如下** :

一维差分数组构造方式:

{

b

[

1

]

=

a

[

1

]

b

[

2

]

=

a

[

2

]

a

[

1

]

b

[

3

]

=

a

[

3

]

a

[

2

]

.

.

.

b

[

n

]

=

a

[

n

]

a

[

n

1

]

一维差分数组构造方式: \begin{cases} b[1] = a[1]\\ b[2] = a[2] - a[1]\\ b[3] = a[3] - a[2]\\ …\\ b[n] = a[n] - a[n - 1] \end{cases}

一维差分数组构造方式:⎩

⎧​b[1]=a[1]b[2]=a[2]−a[1]b[3]=a[3]−a[2]…b[n]=a[n]−a[n−1]​

那么这里的 构造过程 实际上就是遍历一遍

a

a

a 数组,就可以构造出

b

b

b ,**时间复杂度为

O

(

N

)

O(N)

O(N)** 。我们再看看代码怎么写:

for (int i = 1; i <= n; i++) {
        b[i] = a[i] - a[i - 1];
    }

讲完了构造,我们再看看差分这个算法为了解决什么问题

差分算法是为了解决让 **序列中某段区间

[

l

,

r

]

[l, r]

[l,r] 加上一个 常数

c

c

c** 的问题。

放到平时,那么我们肯定是遍历一遍,然后把数据

c

c

c 加上,时间复杂度为

O

(

N

)

O(N)

O(N) ,但是如果使用差分呢?

**假设现在

a

a

a 是原数组,差分数组

b

b

b 已经求好了,此时要让

a

a

a 数组

[

l

,

r

]

[l, r]

[l,r] 区间内

c

+c

+c**,**只需要让

b

[

l

]

=

c

,让

b

[

r

1

]

=

c

\color{red}b[l] += c,让 b[r + 1] -=c

b[l]+=c,让b[r+1]−=c 即可**,**时间复杂度为

O

(

1

)

O(1)

O(1)** 。

如下图:

image-20221223113822828

但是为什么这样就可以了,它的原理是什么?我们还得继续探究

由于

a

a

a 数组是

b

b

b 数组的前缀和,所以让

b

[

l

]

=

c

\color{red}b[l] += c

b[l]+=c ,就会造成如下结果:

b

加上

c

后:

b

[

l

]

=

b

[

l

]

c

a

[

l

]

=

b

[

1

]

b

[

2

]

.

.

.

b

[

l

]

a

[

l

]

=

b

[

1

]

b

[

2

]

.

.

.

b

[

l

]

c

当前

a

[

l

]

已经发生了改变:

a

[

l

]

=

a

[

l

]

c

所以接下来的

a

数组中的元素都会加上

c

a

[

l

1

]

=

a

[

l

]

c

b

[

l

1

]

.

.

.

a

[

n

]

=

a

[

n

1

]

c

b

[

n

]

\begin{align} &b \ 加上 \ c \ 后:b[l] = b[l]’ + c \\ &a[l]’ = b[1] + b[2] + … + b[l]’ \ &\downarrow \ &a[l] = b[1] + b[2] + … + \color{red}b[l]’ + c \ &\downarrow \ &当前 a[l] 已经发生了改变:\color{red}a[l] = a[l]’ + c \ &\downarrow \ &所以接下来的 a 数组中的元素都会加上 c ! \ &\downarrow \ &a[l + 1] = {\color{red}a[l]’ + c} + b[l + 1] \ &\downarrow \ &… \ &\downarrow \ &a[n] = {\color{red}a[n - 1]’ + c} + b[n] \end{align}

​b 加上 c 后:b[l]=b[l]′+ca[l]′=b[1]+b[2]+…+b[l]′↓a[l]=b[1]+b[2]+…+b[l]′+c↓当前a[l]已经发生了改变:a[l]=a[l]′+c↓所以接下来的a数组中的元素都会加上c!↓a[l+1]=a[l]′+c+b[l+1]↓…↓a[n]=a[n−1]′+c+b[n]​​

同理,对于

b

[

r

1

]

=

c

\color{red}b[r + 1] -= c

b[r+1]−=c 也可以推导,下面我就简写一下了:

b

[

r

1

]

=

b

[

r

1

]

c

a

[

r

1

]

=

a

[

r

]

b

[

r

1

]

c

a

[

r

1

]

=

a

[

r

1

]

c

a

[

r

2

]

=

a

[

r

1

]

c

b

[

r

2

]

.

.

.

a

[

n

]

=

a

[

n

1

]

c

b

[

n

]

\begin{align} &b[r + 1] = b[r + 1]’ -c \\ &a[r + 1] = a[r] + b[r + 1]’ - c \ &\downarrow \ &a[r + 1] = a[r + 1]’ - c \ &\downarrow \ &a[r + 2] = a[r + 1]’ - c + b[r + 2] \ &\downarrow \ &… \ &\downarrow \ &a[n] = a[n - 1]’ - c + b[n] \end{align}

​b[r+1]=b[r+1]′−ca[r+1]=a[r]+b[r+1]′−c↓a[r+1]=a[r+1]′−c↓a[r+2]=a[r+1]′−c+b[r+2]↓…↓a[n]=a[n−1]′−c+b[n]​​
**由此,得证只要让

b

[

l

]

=

c

,让

b

[

r

1

]

=

c

\color{red}b[l] += c,让 b[r + 1] -=c

b[l]+=c,让b[r+1]−=c,就可以使

a

a

a 数组中

[

l

.

r

]

[l. r]

[l.r] 区间内元素加上 常数

c

c

c 。**

2、代码实现

高能预警,代码实现这块就是博主觉得比较抽象,但很神奇的地方。

先上题目 ~

链接797.差分

描述

输入一个长度为

n

n

n 的整数序列。

接下来输入

m

m

m 个操作,每个操作包含三个整数

l

,

r

,

c

l,r,c

l,r,c 表示将序列中

[

l

,

r

]

[l,r]

[l,r] 之间的每个数加上

c

c

c 。

请你输出进行完所有操作后的序列。

输入格式:

第一行包含两个整数

n

n

n 和

m

m

m 。

第二行包含

n

n

n 个整数,表示整数序列。

接下来

m

m

m 行,每行包含三个整数

l

r

c

l,r,c

l,r,c 表示一个操作。

输出格式

共一行,包含

n

n

n 个整数,表示最终序列。

数据范围

  • 1

n

,

m

100000

1≤n,m≤100000

1≤n,m≤100000

  • 1

l

r

n

1≤l≤r≤n

1≤l≤r≤n

1000

c

1000

−1000≤c≤1000

−1000≤c≤1000

1000

整数序列中元素的值

1000

−1000≤整数序列中元素的值≤1000

−1000≤整数序列中元素的值≤1000

输入样例

6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1

输出样例

3 4 5 3 4 2

代码1

这段代码就是我们上方 算法推导的完全复刻 ,先构造差分矩阵

b

b

b ,再根据方法对区间进行操作。

b

b

b 数组完成计算之后,对齐求一下 前缀和 ,将数据存到

a

a

a 数组中。

image-20221223115446138

代码2

但是其实 y 老师讲的其实不是这种方法,他用了更加巧妙的一个方式。

y 老师的思路,是将

a

a

a 数组的所有元素全部假定为 0 ,用了一个 insert 函数,不考虑构造,通过对小区间的插入,和对

[

l

,

r

]

[l, r]

[l,r] 区间的处理,直接完成了对区间

[

l

,

r

]

\color{red}[l, r]

[l,r] 的运算。

它的思路是 单个小区间,也可以说是相同区间 进行数据之间的增加,比如:

a

1

a

2

a

3

.

.

.

a

n

[

1

,

1

]

a

[

1

]

[

2

,

2

]

a

[

2

]

.

.

.

[

n

,

n

]

a

[

n

]

a1 \ a2 \ a3 \ … an \ \downarrow \ [1, 1] + a[1] \ \ \ \ [2, 2] + a[2] \ \ \ \ … \ \ \ \ [n, n] + a[n]

a1 a2 a3 …an↓[1,1]+a[1]    [2,2]+a[2]    …    [n,n]+a[n]
每个数据一开始看做 0 ,这样子就像对每个值进行 +c ,再进行之后

[

l

,

r

]

[l, r]

[l,r] 区间的操作,直接求出结果。

这样就忽略了 构建差分数组 ,直接从结果上求解,运用了 差分的特性:对差分数组求前缀和就算得原数组 ,从而直接求得结果。

先来看一眼代码:

image-20221223120915355

我第一眼看到这个代码我就觉得很惊艳,这是一个很巧妙的做法,但是过一会我就十分疑惑

如果我不从最终结果上来看,我就是要看 过程 呢?差分之前说过,第一步就要构建 差分数组 ,之后才能进行求解,但是这里没有构建是怎么算的?

可能是博主比较无聊,就想了好一会,看着代码没想明白,后来把这个过程推了一遍,发现,这一过程真的十分妙!

在上图中,我给出 红色 方框的部分既可以看做对小区间进行数据插入,又可以看做是在构建差分数组。

为什么这么说?下面我们进行一下推导证明:

之间我们推导过如何构造

差分矩阵

b

差分矩阵 b

差分矩阵b ,这里再提一下,这里是 关键

一维差分数组构造方式:

{

b

[

1

]

=

a

[

1

]

b

[

2

]

=

a

[

2

]

a

[

1

]

b

[

3

]

=

a

[

3

]

a

[

2

]

.

.

.

b

[

n

]

=

a

[

n

]

a

[

n

1

]

一维差分数组构造方式: \begin{cases} b[1] = a[1]\\ b[2] = a[2] - a[1]\\ b[3] = a[3] - a[2]\\ …\\ b[n] = a[n] - a[n - 1] \end{cases}

一维差分数组构造方式:⎩

⎧​b[1]=a[1]b[2]=a[2]−a[1]b[3]=a[3]−a[2]…b[n]=a[n]−a[n−1]​
由于

b

b

b 是全局数组,所以一开始元素都是为 0 的。

所以

b

\color{red}b

b 初始状态为:

0

0

0

0

0

0

1

2

3

4

5

6

\begin{align} &\ 0 \ \ \ \ 0 \ \ \ \ 0 \ \ \ \ 0 \ \ \ \ 0 \ \ \ \ 0 \ \ & \ 1 \ \ \ \ 2 \ \ \ \ 3 \ \ \ \ 4 \ \ \ \ 5 \ \ \ \ 6 \end{align}

​ 0    0    0    0    0    0 1    2    3    4    5    6​​

**注:这里第一行为

b

b

b 数组,第二行为 下标 ,由于 LaTeX 我用的还不是很熟练,所以还不能很好的控制对齐和缩进,加上标识这个就不对齐了,效果不太好,所以就省略了~大家看到这条之后委屈一下hh,我会尽量说明白的。**

现在开始模拟这一过程:

  1. 第一次循环,insert(1, 1, a[1]) ,对

[

1

,

1

]

[1, 1]

[1,1] 进行

a

[

1

]

a[1]

a[1] 元素的插入,插入之后结果:

a

[

1

]

a

[

1

]

0

0

0

0

1

2

3

4

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

−1000≤整数序列中元素的值≤1000

−1000≤整数序列中元素的值≤1000

输入样例

6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1

输出样例

3 4 5 3 4 2

代码1

这段代码就是我们上方 算法推导的完全复刻 ,先构造差分矩阵

b

b

b ,再根据方法对区间进行操作。

b

b

b 数组完成计算之后,对齐求一下 前缀和 ,将数据存到

a

a

a 数组中。

image-20221223115446138

代码2

但是其实 y 老师讲的其实不是这种方法,他用了更加巧妙的一个方式。

y 老师的思路,是将

a

a

a 数组的所有元素全部假定为 0 ,用了一个 insert 函数,不考虑构造,通过对小区间的插入,和对

[

l

,

r

]

[l, r]

[l,r] 区间的处理,直接完成了对区间

[

l

,

r

]

\color{red}[l, r]

[l,r] 的运算。

它的思路是 单个小区间,也可以说是相同区间 进行数据之间的增加,比如:

a

1

a

2

a

3

.

.

.

a

n

[

1

,

1

]

a

[

1

]

[

2

,

2

]

a

[

2

]

.

.

.

[

n

,

n

]

a

[

n

]

a1 \ a2 \ a3 \ … an \ \downarrow \ [1, 1] + a[1] \ \ \ \ [2, 2] + a[2] \ \ \ \ … \ \ \ \ [n, n] + a[n]

a1 a2 a3 …an↓[1,1]+a[1]    [2,2]+a[2]    …    [n,n]+a[n]
每个数据一开始看做 0 ,这样子就像对每个值进行 +c ,再进行之后

[

l

,

r

]

[l, r]

[l,r] 区间的操作,直接求出结果。

这样就忽略了 构建差分数组 ,直接从结果上求解,运用了 差分的特性:对差分数组求前缀和就算得原数组 ,从而直接求得结果。

先来看一眼代码:

image-20221223120915355

我第一眼看到这个代码我就觉得很惊艳,这是一个很巧妙的做法,但是过一会我就十分疑惑

如果我不从最终结果上来看,我就是要看 过程 呢?差分之前说过,第一步就要构建 差分数组 ,之后才能进行求解,但是这里没有构建是怎么算的?

可能是博主比较无聊,就想了好一会,看着代码没想明白,后来把这个过程推了一遍,发现,这一过程真的十分妙!

在上图中,我给出 红色 方框的部分既可以看做对小区间进行数据插入,又可以看做是在构建差分数组。

为什么这么说?下面我们进行一下推导证明:

之间我们推导过如何构造

差分矩阵

b

差分矩阵 b

差分矩阵b ,这里再提一下,这里是 关键

一维差分数组构造方式:

{

b

[

1

]

=

a

[

1

]

b

[

2

]

=

a

[

2

]

a

[

1

]

b

[

3

]

=

a

[

3

]

a

[

2

]

.

.

.

b

[

n

]

=

a

[

n

]

a

[

n

1

]

一维差分数组构造方式: \begin{cases} b[1] = a[1]\\ b[2] = a[2] - a[1]\\ b[3] = a[3] - a[2]\\ …\\ b[n] = a[n] - a[n - 1] \end{cases}

一维差分数组构造方式:⎩

⎧​b[1]=a[1]b[2]=a[2]−a[1]b[3]=a[3]−a[2]…b[n]=a[n]−a[n−1]​
由于

b

b

b 是全局数组,所以一开始元素都是为 0 的。

所以

b

\color{red}b

b 初始状态为:

0

0

0

0

0

0

1

2

3

4

5

6

\begin{align} &\ 0 \ \ \ \ 0 \ \ \ \ 0 \ \ \ \ 0 \ \ \ \ 0 \ \ \ \ 0 \ \ & \ 1 \ \ \ \ 2 \ \ \ \ 3 \ \ \ \ 4 \ \ \ \ 5 \ \ \ \ 6 \end{align}

​ 0    0    0    0    0    0 1    2    3    4    5    6​​

**注:这里第一行为

b

b

b 数组,第二行为 下标 ,由于 LaTeX 我用的还不是很熟练,所以还不能很好的控制对齐和缩进,加上标识这个就不对齐了,效果不太好,所以就省略了~大家看到这条之后委屈一下hh,我会尽量说明白的。**

现在开始模拟这一过程:

  1. 第一次循环,insert(1, 1, a[1]) ,对

[

1

,

1

]

[1, 1]

[1,1] 进行

a

[

1

]

a[1]

a[1] 元素的插入,插入之后结果:

a

[

1

]

a

[

1

]

0

0

0

0

1

2

3

4

[外链图片转存中…(img-Jl2GY1Wa-1714737281085)]
[外链图片转存中…(img-EBGmVBYx-1714737281086)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值