AI summary
type
status
date
slug
summary
category
tags
icon
password
前缀和技巧适用于快速、频繁地计算一个索引区间内的元素之和。

一维数组中的前缀和

303. 区域和检索 - 数组不可变

给定一个整数数组  nums,处理以下类型的多个查询:
  1. 计算索引 left 和 right (包含 left 和 right)之间的 nums 元素的  ,其中 left <= right
实现 NumArray 类:
  • NumArray(int[] nums) 使用数组 nums 初始化对象
  • int sumRange(int i, int j) 返回数组 nums 中索引 left 和 right 之间的元素的 总和 ,包含 left 和 right 两点(也就是 nums[left] + nums[left + 1] + ... + nums[right] )
这是一道标准的前缀和问题。核心思路是我们 new 一个新的数组 preSum 出来,preSum[i] 记录 nums[0..i-1] 的累加和,如果我想求索引区间 [1, 4] 内的所有元素之和,就可以通过 preSum[5] - preSum[1] 得出。
这样,sumRange 函数仅仅需要做一次减法运算,避免了每次进行 for 循环调用,时间复杂度为 O(1)。

二维矩阵中的前缀和

304. 二维区域和检索 - 矩阵不可变

给定一个二维矩阵 matrix,以下类型的多个请求:
  • 计算其子矩形范围内元素的总和,该子矩阵的 左上角 为 (row1, col1) ,右下角 为 (row2, col2) 。
实现 NumMatrix 类:
  • NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初始化
  • int sumRegion(int row1, int col1, int row2, int col2) 返回 所描述的子矩阵的元素 总和 。
和上面同理,presum[x][y] 表示 左上角为 (0,0),右下角为 (x,y) 的矩阵元素和。
转移关系如下图所示:
notion image

拓展延伸

本文讲解的前缀和技巧是利用预计算的 preSum 数组快速计算索引区间内的元素和,但实际上它不仅仅局限于求和,也可以用来快速计算区间内的最大值、最小值、乘积等等。
而且前缀和数组经常和其他数据结构或算法技巧相结合,我会在 前缀和技巧经典习题 中结合习题讲解。
还有一个重要的问题:使用前缀和技巧的前提是原数组 nums 不会发生变化
如果原数组中的某个元素改变了,那么 preSum 数组中该元素后面的值就会失效,需要重新花费 O(n) 的时间计算,这就和普通的暴力解法没太大区别了。所以在数组元素可变的场景下,我们不能使用前缀和技巧,而是使用 线段树 这种数据结构来处理区间查询和动态更新。