labuladong_一/二维数组前缀和
一维数组前缀和
核心思路 是我们 new 一个新的数组 preSum
出来,preSum[i]
记录 nums[0..i-1]
的累加和。
前缀和主要适用的场景 是原始数组不会被修改的情况下,频繁查询某个区间的累加和。
preSum[i]
就代表着 nums[0..i-1]
所有元素的累加和,如果我们想求区间 nums[i..j]
的累加和,只要计算 preSum[j+1] - preSum[i]
即可,而不需要遍历整个区间求和。看这个 preSum
数组,如果我想求索引区间 [1, 4]
内的所有元素之和,就可以通过 preSum[5] - preSum[1]
得出。
二维数组前缀和
比如说输入的 matrix
如下图:
按照题目要求,矩阵左上角为坐标原点 (0, 0)
,那么 sumRegion([2,1,4,3])
就是图中红色的子矩阵,你需要返回该子矩阵的元素和 8。
当然,你可以用一个嵌套 for 循环去遍历这个矩阵,但这样的话 sumRegion
函数的时间复杂度就高了,你算法的格局就低了。
注意任意子矩阵的元素和可以转化成它周边几个大矩阵的元素和的运算:
而这四个大矩阵有一个共同的特点,就是左上角都是 (0, 0)
原点。
那么做这道题更好的思路和一维数组中的前缀和是非常类似的,我们可以维护一个二维 preSum
数组,专门记录以原点为顶点的矩阵的元素之和,就可以用几次加减运算算出任何一个子矩阵的元素和:
class NumMatrix {
// 定义:preSum[i][j] 记录 matrix 中子矩阵 [0, 0, i-1, j-1] 的元素和
private int[][] preSum;
public NumMatrix(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
if (m == 0 || n == 0) return;
// 构造前缀和矩阵
preSum = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// 计算每个矩阵 [0, 0, i, j] 的元素和
preSum[i][j] = preSum[i-1][j] + preSum[i][j-1] + matrix[i - 1][j - 1] - preSum[i-1][j-1];
}
}
}
// 计算子矩阵 [x1, y1, x2, y2] 的元素和
public int sumRegion(int x1, int y1, int x2, int y2) {
// 目标矩阵之和由四个相邻矩阵运算获得
return preSum[x2+1][y2+1] - preSum[x1][y2+1] - preSum[x2+1][y1] + preSum[x1][y1];
}
}
这样,sumRegion
函数的时间复杂度也用前缀和技巧优化到了 O(1),这是典型的「空间换时间」思路。
java基础知识
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话