在leetcode有一些题利用的是前缀和方法,很多时候都用的是图形法解,一开始还是有点费解的,特别是对于我这样不太擅长图形转化成公式的人来说。本文用的单纯的数学推导得到递推公式,理解的基础上直接用代码实现公式。
前缀和思路在于区域相减,以leetcode的304题为例子
S
[
r
o
w
1
,
r
o
w
2
]
[
c
o
l
1
,
c
o
l
2
]
=
Σ
r
o
w
1
r
o
w
2
Σ
c
o
l
1
c
o
l
2
M
a
t
i
x
[
i
]
[
j
]
S[row1,row2][col1,col2] = \Sigma_{row1}^{row2}\Sigma_{col1}^{col2} Matix[i][j]
S[row1,row2][col1,col2]=Σrow1row2Σcol1col2Matix[i][j]
其中,
i
∈
[
r
o
w
1
,
r
o
w
2
]
,
j
∈
[
c
o
l
1
,
c
o
l
2
]
i\in[row1,row2],j\in[col1,col2]
i∈[row1,row2],j∈[col1,col2]
伪代码为
int sum = 0;
for i from row1 -> row2
for j from col1 -> col2
sum = sum + Matrix[i][j]
return sum
但是在上述求解过程中不难发现求解S[i][j]会反复计算Matrix[0][0],Matrix[0][1],Matrix[1][0]…求解区域越大前面的元素被求解调用的次数越多,其实不难发现就是存在重复子问题,可以考虑动态规划,借用之前图形就是
S
[
D
]
=
S
[
D
t
o
t
a
l
]
−
S
[
A
]
−
S
[
B
]
+
S
[
C
]
S[D] =S[D_{total}] -S[A] - S[B] + S[C]
S[D]=S[Dtotal]−S[A]−S[B]+S[C]
其中
S
[
D
t
o
t
a
l
]
S[D_{total}]
S[Dtotal] 为D区域右下角坐标到原点的求和。由上式不难发现,子问题被存储在数组S中,避免了反复对Matrix的求和。
针对
S
[
D
]
S[D]
S[D]求解,计算公式为
S
[
D
x
]
[
D
y
]
=
Σ
0
D
x
Σ
0
D
y
M
a
t
i
x
[
i
]
[
j
]
S[D_x][D_y] = \Sigma_{0}^{D_x}\Sigma_{0}^{D_y} Matix[i][j]
S[Dx][Dy]=Σ0DxΣ0DyMatix[i][j] ,这个问题一样,反复求解之前数据,思路和之前一样,如果直接求解,就是遍历 $[0,D_x],[0,D_y] $区间,针对求和公式分解,定义
S
[
k
x
]
[
k
y
]
S[k_x][k_y]
S[kx][ky] 为坐标点k的,由原点到该坐标的方块区域内坐标点求和
因为
S
[
k
x
−
1
]
[
k
y
]
=
Σ
0
k
x
−
1
Σ
0
k
y
M
a
t
r
i
x
[
i
]
[
j
]
=
Σ
0
k
x
−
1
M
a
t
r
i
x
[
i
]
[
k
y
]
+
Σ
0
k
x
−
1
Σ
0
k
y
−
1
M
a
t
r
i
x
[
i
]
[
j
]
S[k_x-1][k_y] =\Sigma_{0}^{k_x-1}\Sigma_{0}^{k_y}Matrix[i][j] = \Sigma_{0}^{k_x-1}Matrix[i][k_y] + \Sigma_{0}^{k_x-1}\Sigma_{0}^{k_y-1}Matrix[i][j]
S[kx−1][ky]=Σ0kx−1Σ0kyMatrix[i][j]=Σ0kx−1Matrix[i][ky]+Σ0kx−1Σ0ky−1Matrix[i][j]同理对于$ S[k_x][k_y-1] $不难推导得到,而
S
[
k
x
−
1
]
[
k
y
−
1
]
=
Σ
0
k
x
−
1
Σ
0
k
y
−
1
M
a
t
r
i
x
[
i
]
[
j
]
S[k_x -1][k_y-1] = \Sigma_{0}^{k_x-1}\Sigma_{0}^{k_y-1}Matrix[i][j]
S[kx−1][ky−1]=Σ0kx−1Σ0ky−1Matrix[i][j]即为重叠区域,上述递推式子即只需要每次加上 Matrix[i][j] 即可,而无需反复求和,利用空间换时间
总结起来就是两个递推式