知识来源:刷题 :蓝桥杯https://www.dotcpp.com/oj/problem2659.html
prefixSum[i][j] = prefixSum[i - 1][j] + prefixSum[i][j - 1] - prefixSum[i - 1][j - 1] + grid[i - 1][j - 1];
//grid是输入的数据,prefixSum是我们用来记录二维前缀和的数组
这个公式用于计算二维前缀和数组 prefixSum
中的每个元素的值,其背后的逻辑基于容斥原理。让我们逐步解释这个公式:
首先,二维前缀和数组 prefixSum
的每个元素 prefixSum[i][j]
表示原数组 grid
中从 (0, 0)
到 (i-1, j-1)
的所有元素的和。换句话说,prefixSum[i][j]
是以 (i-1, j-1)
为右下角的矩形区域内所有元素的和。
为了计算 prefixSum[i][j]
,我们需要考虑以下几个部分:
prefixSum[i - 1][j]
:这是从(0, 0)
到(i-2, j-1)
的矩形区域内所有元素的和。prefixSum[i][j - 1]
:这是从(0, 0)
到(i-1, j-2)
的矩形区域内所有元素的和。prefixSum[i - 1][j - 1]
:这是从(0, 0)
到(i-2, j-2)
的矩形区域内所有元素的和。
当我们试图计算 prefixSum[i][j]
时,我们实际上想要的是从 (0, 0)
到 (i-1, j-1)
的和,这包括两部分:
- 从
(0, 0)
到(i-2, j-1)
的和(即prefixSum[i - 1][j]
)。 - 从
(0, 0)
到(i-1, j-2)
的和(即prefixSum[i][j - 1]
)。
但是,这两部分都重复计算了从 (0, 0)
到 (i-2, j-2)
的和,这部分和是 prefixSum[i - 1][j - 1]
。因此,我们需要从 prefixSum[i - 1][j]
和 prefixSum[i][j - 1]
的和中减去 prefixSum[i - 1][j - 1]
,以避免重复计算。
最后,我们加上 grid[i - 1][j - 1]
,这是当前位置 (i-1, j-1)
的值,它尚未被包含在前述任何和中。
prefixSum[i][j] = prefixSum[i - 1][j] + prefixSum[i][j - 1] - prefixSum[i - 1][j - 1] + grid[i - 1][j - 1]
这个公式允许我们高效地计算二维前缀和数组,因为每个元素只依赖于其左侧、上方和左上方的元素,这样我们就可以在 O(mn) 的时间复杂度内填充整个 prefixSum
数组,其中 m 和 n 分别是 grid
的行数和列数。