Skip to content

Commit

Permalink
前缀和
Browse files Browse the repository at this point in the history
  • Loading branch information
yk committed Feb 19, 2024
1 parent ded7ed8 commit a5655c4
Showing 1 changed file with 68 additions and 23 deletions.
91 changes: 68 additions & 23 deletions content/posts/algorithm/data structure/数组-前缀和数组.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@ series: [data structure, trick]
categories: [algorithm]
---

## 基础
## 概念

应用场景:在原始数组不会被修改的情况下,**快速、频繁查询某个区间的累加和**

核心思路:开辟新数组 `preSum[i]` 来存储原数组 `nums[0..i-1] `的累加和,`preSum[0] = 0`。这样,当求原数组区间和就比较容易了,区间 `[i..j]` 的和等于 `preSum[j+1] - preSum[i]` 的结果值。

```JavaScript
const preSum = [0]

preSum[i] = preSum[i - 1] + nums[i - 1]
// 查询
preSum[r + 1] - preSum[l]

// 或者
const preSum = [nums[0]]
preSum[i] = preSum[i-1] + nums[i]
// 查询
preSum[r] - preSum[l-1] // 需要判断 l 为 0 的情况,直接返回 preSum[r],这种的劣势是需要判断边界条件
```

### 构造:[303.区域和检索-数组不可变](https://leetcode.cn/problems/range-sum-query-immutable/)
Expand All @@ -25,8 +32,8 @@ preSum[i] = preSum[i - 1] + nums[i - 1]
* @param {number[]} nums
*/
var NumArray = function(nums) {
this.preSum = [0] // presum 首位为0 便于计算
for(let i = 1; i <= nums.length; ++i) { // 遍历数组的每一个元素, 因为使用的是nums[i-1]
this.preSum = [0] // preSum 首位为0 便于计算
for(let i = 1; i <= nums.length; ++i) {
this.preSum[i] = this.preSum[i - 1] + nums[i -1]
}
};
Expand All @@ -47,40 +54,78 @@ NumArray.prototype.sumRange = function(left, right) {
*/
```

---

上方那种事官解给出的逻辑,下面这种可能更容易理解一些。

```js
/**
* @param {number[]} nums
*/
var NumArray = function (nums) {
this.preSums = [nums[0]]
for (let i = 1; i < nums.length; ++i) {
this.preSums[i] = this.preSums[i - 1] + nums[i]
}
}

/**
* @param {number} left
* @param {number} right
* @return {number}
*/
NumArray.prototype.sumRange = function (left, right) {
if (left === 0) return this.preSums[right]
return this.preSums[right] - this.preSums[left - 1]
}

/**
* Your NumArray object will be instantiated and called as such:
* var obj = new NumArray(nums)
* var param_1 = obj.sumRange(left,right)
*/
```

### 构造:[304. 二维区域和检索-矩阵不可变](https://leetcode.cn/problems/range-sum-query-2d-immutable/)

```js
/**
* @param {number[][]} matrix
*/
var NumMatrix = function (matrix) {
const m = matrix.length,
n = matrix[0].length
if (m == 0 || n == 0) return
// 第一行,第一列填充为0方便计算
this.presum = new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(0))
// 遍历presum,因为要填充到最后一个,所以是闭区间,使用小于等于,所以前缀和的索引超前matrix 1位
for (let i = 1; i <= m; ++i) {
for (let j = 1; j <= n; ++j) {
// 计算矩阵[]0,0,i,j],减去部分为重复部分
this.presum[i][j] =
this.presum[i - 1][j] +
this.presum[i][j - 1] -
this.presum[i - 1][j - 1] +
matrix[i - 1][j - 1]
// 当前块的区域和等于以matrix[0,0]为定点四个区域块的加减得来,其中左上角有一块会被加两次所以要减掉一次
const row = matrix.length
const col = matrix[0].length
this.sums = Array.from(Array(row + 1), () => Array(col + 1).fill(0))
for (let i = 0; i < row; ++i) {
for (let j = 0; j < col; ++j) {
this.sums[i + 1][j + 1] =
this.sums[i + 1][j] + this.sums[i][j + 1] - this.sums[i][j] + matrix[i][j]
}
}
console.log(this.sums)
}

/**
* @param {number} row1
* @param {number} col1
* @param {number} row2
* @param {number} col2
* @return {number}
*/
NumMatrix.prototype.sumRegion = function (row1, col1, row2, col2) {
return (
this.presum[row2 + 1][col2 + 1] +
this.presum[row1][col1] -
this.presum[row1][col2 + 1] -
this.presum[row2 + 1][col1]
this.sums[row2 + 1][col2 + 1] -
this.sums[row1][col2 + 1] -
this.sums[row2 + 1][col1] +
this.sums[row1][col1]
)
}

/**
* Your NumMatrix object will be instantiated and called as such:
* var obj = new NumMatrix(matrix)
* var param_1 = obj.sumRegion(row1,col1,row2,col2)
*/
```

### 应用:[560.和为 k 的子数组](https://leetcode.cn/problems/subarray-sum-equals-k/)
Expand Down

0 comments on commit a5655c4

Please sign in to comment.