二维前缀和与二维差分数组

news/2025/11/17 20:20:17/文章来源:https://www.cnblogs.com/coding-memory/p/19234298

二维前缀和与二维差分数组

二维前缀和

定义

给定一个m行n列的矩阵,它的前缀和sum[i][j]定义为前i行中前i列所有区域格子元素的累加和, 即\(sum[i+1][j+1] = \sum\limits_{row=0, col=0}^{i, j} matrix[row][col]\), 由定义易得二维前缀和的递推公式为 sum[i + 1][j + 1] = matrix[i][j] + sum[i][j + 1] + sum[i + 1][j] - sum[i][j]。

假设查询区域为左上角(r1, c1)到右下角(r2, c2)范围内元素的累加和, 借助二维前缀和同样可以将单次查询时间复杂度降低到O(1), 计算公式为 sum[r2 + 1][c2 + 1] - sum[r2 + 1][c1] - sum[r1][c2 + 1] + sum[r1][c1], 下图是对该公式的直观解释:

代码示例

可直接在 【LeetCode 304】二维区域和检索 - 矩阵不可变 执行提交测试:

class NumMatrix {private int[][] sum;public NumMatrix(int[][] matrix) {int m = matrix.length, n = matrix[0].length;sum = new int[m + 1][n + 1];for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {sum[i + 1][j + 1] = matrix[i][j] + sum[i][j + 1] + sum[i + 1][j] - sum[i][j];}}}public int sumRegion(int row1, int col1, int row2, int col2) {return sum[row2 + 1][col2 + 1] - sum[row2 + 1][col1] - sum[row1][col2 + 1] + sum[row1][col1];}
}

二维差分数组

引言

延续一维前缀和与差分数组的关联思想, 为了将二维数组的区域修改借助差分实现单次操作仅需O(1)时间复杂度, 同样需要借助二维差分数组。

与原始二维数组的互相转换

由于最终差分数组是通过计算前缀和来得到原数组, 所以从前缀和递推公式 sum[i + 1][j + 1] = matrix[i][j] + sum[i][j + 1] + sum[i + 1][j] - sum[i][j] 来反推, 由原数组初始化差分数组的递推公式为 diff[i][j] = matrix[i + 1][j + 1] - matrix[i][j + 1] - matrix[i + 1][j] + matrix[i][j], 同样为了方便处理首行首列数据通常二维差分也会在首行首列前预添加全为0的格子, 以下是二维差分与原始数组互相转换的代码示例:

   private int[][] init(int[][] matrix) {int m = matrix.length, n = matrix[0].length;// 实际应用中为了后续修改和最终求前缀和方便, 差分数组首末行列都会各添加一行/列int[][] diff = new int[m + 2][n + 2];for (int i = 0; i < m; i++) {diff[i + 1][1] = matrix[i][0];}for (int j = 0; j < n; j++) {diff[1][j + 1] = matrix[0][j];}for (int i = 1; i < m; j++) {for (int j = 1; j < n; j++) {diff[i + 1][j + 1] = matrix[i][j] - matrix[i - 1][j] - matrix[i][j - 1] + matrix[i - 1][j - 1]; }}return diff;}private int[][] convert(int[][] diff) {int m = diff.length - 2, n = diff[0].length - 2;int[][] sum = new int[m][n];for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {diff[i + 1][j + 1] += diff[i][j + 1] + diff[i + 1][j] - diff[i][j];sum[i][j] = diff[i + 1][j + 1];}}return sum;}

批量修改二维区域与差分数组的关系

假设要求将二维数组从左上角(r1, c1)到右下角(r2, c2)区域的元素值统一增加, 只要借助更新常数个差分数组中的元素值就能实现, 结合下图来解释具体对应哪几个下标元素以及为什么:

  1. 黄红蓝灰四色区域代表的前缀和受影响范围是由左上角格子(r1 + 1, c1 + 1), 也就是对应差分数组中diff[r1 + 1][c1 + 1] += val;
  2. 排除红+灰区域代表的前缀和不受影响, 对应差分数组中diff[r1 + 1][c2 + 2] -= val;
  3. 同理排除蓝+灰区域不受影响是对应diff[r2 + 2][c1 + 1] -= val;
  4. 两次排除时灰色区域操作了两次需要再回撤一次, 对应再将diff[r2 + 2][c2 + 2] += val;
  5. 最终通过更新4个差分数组中的元素达到仅影响其前缀和范围中黄色部分的目的, 也就是对原数组中指定区域统一增加了val。

代码示例如下:

   private void add(int[][] diff, int r1, int c1, int r2, int c2, int val) {diff[r1 + 1][c1 + 1] += val;diff[r1 + 1][c2 + 2] -= val;diff[r2 + 2][c1 + 1] -= val;diff[r2 + 2][c2 + 2] -= val;}

相关题目

【题集】前缀和与差分数组

写在最后

二维差分不太好单独理解, 但是结合二维前缀和以及画图就比较清晰易懂了, 代码实现时根据个人习惯来决定是否要预添加全为0的行/列避免下标越界判断。 这次也是前几天每日一题中有用到而且被下标对应关系绕的有点晕才想起来整理相关内容, 本内容目前仅限于自己由一维前缀和与差分的关系延伸学习理解的总结, 后续有空再结合 B站左神相关视频 继续学习看有没有缺漏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/968268.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

白嫖MegaLLM–175刀免费额度,使用各种AI模型

@目录0.简介1. 注册就送 75 刀额度2. 邀请码3. discord 社区 0.简介 MegaLLM 是一个 API 中转服务,支持主流模型 OpenAI、Anthropic、Google、Meta 等,以及包括国产千问、DeepSeek、GLM、K2 等。可以在 Claude Code、…

复合剩余问题

Carmichael 函数 \(\lambda(n)\) 定义: 对于正整数 \(n\),Carmichael 函数 \(\lambda(n)\) 定义为最小的正整数 \(m\),使得对于所有与 \(n\) 互素的整数 \(a\),都有: \( a^m \equiv 1 \pmod{n} \) 性质:\(\lambd…

CF2165D Path Split 题解

Description 给定一个长度为 \(n\) 的整数序列 \(a_1, a_2, \ldots, a_n\)。 你希望把 \(a\) 划分成若干个子序列 \(b_1, b_2, \ldots, b_k\),并满足以下条件:\(a\) 中的每个元素恰好属于某个 \(b_i\); 对于每个子序…

gdb 安装linux

要安装 gdb(GNU Debugger)在 Linux 系统上,通常有以下几种方法,适用于大多数 Linux 发行版:? 方法 1:使用包管理器(推荐) 大多数 Linux 发行版都通过包管理器安装 gdb,例如: Debian/Ubuntu sudo apt update…

g for linux

看起来您可能输入有误,想问的是:+ #引号 + grep for linux + #引号 + 或 + #引号 + grep in linux + #引号 + ,这是在 Linux 中常用的命令,用于在文件中搜索特定字符串。? 一、grep 命令简介 grep 是 L…

人工智能之编程基础 Python 入门:第十章 文件读写

人工智能之编程基础 Python 入门:第十章 文件读写人工智能之编程基础 Python 入门 第十章 文件读写@目录人工智能之编程基础 Python 入门前言1. 基本文件操作1.1 打开文件:open()1.2 推荐方式:使用 with 语句(上下…

连续段 DP

连续段 DP 主要是做对于序列的计数类问题,其中对序列的限制一般是相邻数要满足一些条件。同时这个序列一般是一个排列。 连续段 DP 的主要思路是依照限制以此往序列里面填数。但是这个填数的过程是动态的,也就是我们…

深入探讨React源码与实现原理

我将从几个核心层面来展开,这也可以作为你自我审视和深入研究的路线图。 一、核心架构:Fiber 架构 这是现代React的基石。理解Fiber是理解一切新特性(如Concurrent Mode、Suspense)的前提。 你需要能清晰地阐述:F…

人工智能之编程基础 Python 入门:第九章 模块与包

人工智能之编程基础 Python 入门:第九章 模块与包人工智能之编程基础 Python 入门 第九章 模块与包@目录人工智能之编程基础 Python 入门前言模块1. 模块的基本概念什么是模块?2. 导入模块1. import 语句2. from ...…

基于Playwright + Allure + Pytest 企业级UI录制与回放自动化测试项目

基于Playwright + Allure + Pytest 企业级UI录制与回放自动化测试项目录制脚本: UI回放开始: 生成测试报告:

IM SDK选型避坑指南,2025年最新10家服务商稳定性排名

IM SDK选型避坑指南,2025年最新10家服务商稳定性排名随着移动互联网的深入发展,即时通讯已渗透到各行各业,从日常的社交聊天到关键业务的金融交易、远程医疗、在线教育,稳定可靠的IM服务成为保障用户体验和业务连续…

自定义yml激活进本地通用yml

自定义yml激活进本地通用yml 核心结论:自定义 YML 可通过「继承引用」「合并配置」或「指定加载顺序」三种方式,激活并复用本地通用 YML 的配置。 关键实现方式Spring Boot 场景(最常用):通用 YML 作为 base 配置…

AT_jsc2019_qual_e Card Collector

首先考虑什么情况不合法。假设 \(S\) 为选出卡片的集合,玩一下发现不合法当且仅当存在 \(T\subseteq S\),\(X=\{x|(x,y)\in T\}\),\(Y=\{y|(x,y)\in T\}\) 满足 \(|X|+|Y|<|T|\)。 假设当前需要加入一个点 \((x_…

人工智能之编程基础 Python 入门:第八章 函数与装饰器

人工智能之编程基础 Python 入门:第八章 函数与装饰器人工智能之编程基础 Python 入门 第八章 函数与装饰器@目录人工智能之编程基础 Python 入门前言函数1. 函数的定义与调用基本语法简单示例2. 函数的组成部分3. 参…

邻项交换

又称微扰法等 例题 最小化最大延迟惩罚 有 n 个任务,每个任务有一个有用时 \(p_i\) 和一个截止时间 \(d_i\),若完成时间为 \(c_i\),要最小化 \(max{c_i - d_i}\)。 考虑如果有两个相邻的 \(i\) 和 \(j\),不交换答案…

day26-MCP基础

MCP快速入门实战 一、MCP技术体系介绍 MCP,全称是Model Context Protocol,模型上下文协议,由Claude母公司Anthropic于2024年11月正式提出。MCP解决的最大痛点,就是Agent开发中调用外部工具的技术门槛过高的问题。 …