前缀和与差分(二维)

二维前缀和

下面是一个二维数组,我们要求(1,1)到(2,2)区间内的所有元素的和,最原始的方法就是遍历每个元素然后一个一个加起来,此时时间复杂度为O(n*m)。
在这里插入图片描述
我们之前学过一维数组的前缀和那么我们可以这样优化一下,
在这里插入图片描述
此时时间复杂度优化到了O(min{n,m})。还可以在优化吗?
答案是可以的。
我们依然根据一维数组的前缀和的思想来考虑二维数组
在这里插入图片描述
在上面的公式中我们发现出现了i-1和j-1,那么我们就需要考虑边界防止i或j为0时造成数组越界,
1.当i=0j=0 我们可以得到sum[0][0]=g[0][0]sum{0,0}{0,0}=g[0][0]
2.当i=0 我们可以得到sum[0][i]=sum[0][i-1]+g[0][i](一维数组前缀和)
sum{0,y1}{0,y2}=sum[0][y2]-sum[0][y1-1]
3.当j=0 我们可以得到sum[i][0]=sum[i-1][0]+g[i][0](一维数组前缀和)和sum{x1,0}{x2,0}=sum[x2][0]-sum[x1-1][0]
在这里插入图片描述

代码如下

#include<iostream> // 包含输入输出流的头文件
using namespace std; // 使用标准命名空间const int n = 3, m = 4; // 定义二维数组的行数n和列数m
int g[n][m] = { {1,5,6,8},{9,6,7,3},{5,3,2,4}}; // 初始化二维数组g
int sum[n][m]; // 用于存储前缀和的二维数组// 计算二维数组的前缀和
void pre_sum()
{sum[0][0] = g[0][0]; // 左上角元素的前缀和为其自身// 计算第一列的前缀和,只需逐行累加for (int i = 1; i < n; i++){sum[i][0] = sum[i - 1][0] + g[i][0]; // 当前元素=上一行同一列元素的前缀和+当前元素}// 计算第一行的前缀和,只需逐列累加for (int j = 1; j < m; j++){sum[0][j] = sum[0][j - 1] + g[0][j]; // 当前元素=前一列同一行元素的前缀和+当前元素}// 计算剩余部分的前缀和for (int i = 1; i < n; i++){for (int j = 1; j < m; j++){// 二维前缀和公式:// 当前元素的前缀和 = 当前元素值 + 上一行同一列前缀和 + 当前行前一列前缀和 - 左上角重叠部分的前缀和sum[i][j] = g[i][j] + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];}}
}// 获取子矩阵的元素和,(x1, y1)为左上角坐标,(x2, y2)为右下角坐标
int get_sum(int x1, int y1, int x2, int y2)
{// 如果左上角坐标是(0,0),直接返回sum[x2][y2]的值if (!x1 && !y1){return sum[x2][y2];}// 如果x1是0,说明子矩阵的上边界在第一行// 结果为整个矩形的前缀和减去子矩阵左侧部分的前缀和if (!x1){return sum[x2][y2] - sum[x2][y1 - 1];}// 如果y1是0,说明子矩阵的左边界在第一列// 结果为整个矩形的前缀和减去子矩阵上方部分的前缀和if (!y1){return sum[x2][y2] - sum[x1 - 1][y2];}// 其他情况,返回整个矩形的前缀和,减去子矩阵左侧和上方的前缀和,并加上左上角重叠部分的前缀和return sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1];
}int main()
{pre_sum(); // 先计算前缀和// 输出从(1, 1)到(2, 2)的子矩阵和,以及从(0, 1)到(1, 3)的子矩阵和cout << get_sum(1, 1, 2, 2) << " " << get_sum(0, 1, 1, 3);return 0; // 程序结束
}

二维差分

有一个二维数组我们对某个区间内的所有元素进行加减操作,如下图所示
在这里插入图片描述
我们在一维数组中操作的时候我们是打标记,在d数组中某个下标的元素+1,他会影响到后面的所有元素,那么假如说我们在二维数组中的二维数组d中某个元素+1会影响那些元素呢?
在这里插入图片描述
我们可以发现在二维数组中我们需要打四个标记通过这个图我们可以写出这样的公式,我们对一个初始化为0的数组d进行操作,根据差分标记来改变数组d,然后对数组d进行前缀和,得到前缀和数组sumd,最后将前缀和数组加到原来的数组即可。
在这里插入图片描述

代码如下

#include<iostream> // 包含输入输出流的头文件
using namespace std; // 使用标准命名空间const int n = 3, m = 4; // 定义二维数组的行数n和列数m
int g[n][m] = { {1,5,6,8},{9,6,7,3},{5,3,2,4} }; // 初始化二维数组g,用于存储原始矩阵
int sum[n][m]; // 用于存储前缀和的二维数组
int d[n + 1][m + 1] = { 0 }; // 定义二维差分数组d,多一行一列以处理边界问题// 计算前缀和并更新g数组
void pre_sum()
{sum[0][0] = d[0][0]; // 左上角的前缀和为差分数组d的值// 计算第一列的前缀和,只需逐行累加for (int i = 1; i < n; i++){sum[i][0] = sum[i - 1][0] + d[i][0];}// 计算第一行的前缀和,只需逐列累加for (int j = 1; j < m; j++){sum[0][j] = sum[0][j - 1] + d[0][j];}// 计算其余部分的前缀和for (int i = 1; i < n; i++){for (int j = 1; j < m; j++){// 二维前缀和公式sum[i][j] = d[i][j] + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];}}// 将差分作用应用到原始矩阵g上for (int i = 0; i < n; i++){for (int j = 0; j < m; j++){g[i][j] += sum[i][j]; // 更新g[i][j]为修改后的值}}
}// 输出矩阵g
void print()
{for (int i = 0; i < n; i++) // 遍历每一行{for (int j = 0; j < m; j++) // 遍历每一列{cout << g[i][j] << " "; // 输出g矩阵中的元素}cout << endl; // 换行}
}// 获取子矩阵的元素和,(x1, y1)为左上角坐标,(x2, y2)为右下角坐标
int get_sum(int x1, int y1, int x2, int y2)
{if (!x1 && !y1){return sum[x2][y2]; // 如果子矩阵的左上角是(0,0),直接返回sum[x2][y2]}if (!x1){return sum[x2][y2] - sum[x2][y1 - 1]; // 如果子矩阵在第一行,减去左侧部分的前缀和}if (!y1){return sum[x2][y2] - sum[x1 - 1][y2]; // 如果子矩阵在第一列,减去上方部分的前缀和}// 其他情况,使用前缀和公式计算子矩阵的和return sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1];
}// 在差分数组d上应用区间更新
void add(int x1, int y1, int x2, int y2, int val)
{// 根据二维差分数组的性质,更新四个点d[x1][y1] += val;          // 左上角增加vald[x2 + 1][y1] -= val;      // 下方减去vald[x1][y2 + 1] -= val;      // 右侧减去vald[x2 + 1][y2 + 1] += val;  // 右下角加上val
}// 输出差分数组d
void printD()
{for (int i = 0; i < n + 1; i++) // 遍历差分数组的行{for (int j = 0; j < m + 1; j++) // 遍历差分数组的列{cout << d[i][j] << " "; // 输出d矩阵中的元素}cout << endl; // 换行}
}int main()
{// 调用add函数,进行两次区间更新add(0, 0, 2, 1, 3);  // 在区域(0,0)到(2,1)增加3add(1, 1, 2, 2, -1); // 在区域(1,1)到(2,2)减少1// printD(); // 如果想调试差分数组d的状态,可以取消注释这一行pre_sum(); // 计算前缀和并更新矩阵gprint();   // 输出更新后的矩阵greturn 0; // 程序结束
}

二位前缀和与二维差分源码

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【计算机网络篇】电路交换,报文交换,分组交换

本文主要介绍计算机网络中的电路交换&#xff0c;报文交换&#xff0c;分组交换&#xff0c;文中的内容是我认为的重点内容&#xff0c;并非所有。参考的教材是谢希仁老师编著的《计算机网络》第8版。跟学视频课为河南科技大学郑瑞娟老师所讲计网。 目录 &#x1f3af;一.划分…

【实战篇】MySQL是怎么保证主备一致的?

MySQL 主备的基本原理 如图 1 所示就是基本的主备切换流程。 在状态 1 中&#xff0c;客户端的读写都直接访问节点 A&#xff0c;而节点 B 是 A 的备库&#xff0c;只是将 A 的更新都同步过来&#xff0c;到本地执行。这样可以保持节点 B 和 A 的数据是相同的。 当需要切换的…

PostgreSQL JAVA与SQL集成之PL/Java

PostgreSQL pljava PL/Java 作为 PostgreSQL 的编程语言扩展之一&#xff0c;与 PL/pgSQL&#xff08;PostgreSQL 原生的存储过程语言&#xff09;相比&#xff0c;提供了 Java 语言特有的面向对象功能&#xff0c;并支持 Java 的标准库和第三方库。由于 Java 是一种跨平台的语…

企业搭建VR虚拟展厅,如何选择搭建平台?

选择虚拟展厅搭建平台时&#xff0c;需要综合考虑多个因素以确保平台能够满足您的具体需求并提供高质量的展示效果。以下是一些关键的选择标准&#xff1a; 1. 技术实力与创新能力 技术平台选择&#xff1a;确保平台支持虚拟现实&#xff08;VR&#xff09;、增强现实&#xf…

Qt clicked()、clicked(bool)、toggled(bool)信号的区别和联系

clicked() 信号 所属控件&#xff1a;clicked()信号是QAbstractButton类&#xff08;及其子类&#xff0c;如QPushButton、QRadioButton、QCheckBox等&#xff09;的一个信号。clicked信号可以说是许多控件&#xff08;特别是按钮类控件&#xff0c;如QPushButton&#xff09;…

基于lnmp搭建wordpress

一、案例目标 &#xff08;1&#xff09;了解LNMP环境的组成。 &#xff08;2&#xff09;了解LNMP环境的部署与安装。 &#xff08;2&#xff09;了解WordPress应用的部署与使用。 二、节点规划 IP 主机名 节点 192.168.200.20 lnmp lnmp服务节点 三、案例实施 LN…

C#基于SkiaSharp实现印章管理(8)

上一章虽然增加了按路径绘制文本&#xff0c;支持按矩形、圆形、椭圆等路径&#xff0c;但测试时发现通过调整尺寸、偏移量等方式不是很好控制文本的位置。相对而言&#xff0c;使用弧线路径&#xff0c;通过弧线起始角度及弧线角度控制文本位置更简单。同时基于路径绘制文本时…

2024 新手指南:轻松掌握 Win10 的录屏操作

之前为了节约成本我们公司都采用录制软件操作都方式来为异地的同事进行远程操作培训的。所以我们尝试了不少的录屏工具&#xff0c;这里我就分享下win10怎么录屏的操作过程。 1.福昕录屏大师 链接&#xff1a;www.foxitsoftware.cn/REC/ 这款录屏工具是初学者的理想之选&…

Linux入门2

文章目录 一、Linux基本命令1.1 文件的创建和查看命令1.2 文件的复制移动删除等命令1.3 查找命令1.4 文件的筛选和管道的使用1.5 echo、tail和重定向符 二、via编辑器三、权限控制3.1 root用户&#xff08;超级管理员&#xff09;3.2 用户和用户组3.3 权限信息3.4 chmod命令 一…

【python设计模式4】结构型模式1

目录 适配器模式 桥模式 适配器模式 将一个类的接口转换成客户希望的另外一个接口&#xff0c;适配器使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。实现适配器的两种方式&#xff0c;类适配器使用多继承&#xff0c;对象适配器使用组合。组合就是一个类中放入另…

Django-cookie和session

文章目录 前言CookieSession 一、Django 中 Cookie二、Django 中 Session三.区别 前言 Cookie Cookie 是由服务器发送到用户浏览器的小文件&#xff0c;用于存储用户的相关信息。每次用户访问网站时&#xff0c;浏览器会将这些 cookie 发送回服务器 特点: 1. 数据存储在客户…

网络质量劣化分析:保障业务连续性与网络优化的核心步骤

目录 什么是网络质量劣化&#xff1f; 常见的网络质量劣化表现 网络质量劣化的常见原因 1. 网络设备性能不足或老化 2. 网络配置问题 3. 链路拥塞 4. 外部攻击或恶意流量 案例分析&#xff1a;一次企业内部网络劣化的解决过程 如何防止网络质量劣化&#xff1f; 结语…

【图像检索】基于傅里叶描述子的形状特征图像检索,matlab实现

博主简介&#xff1a;matlab图像代码项目合作&#xff08;扣扣&#xff1a;3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于傅里叶描述子的形状特征图像检索&#xff0c;用matlab实现。 一、案例背景和算法…

Python 序列( 列表 字典 元组 集合)

列表简介&#xff1a; 1.列表&#xff1a;用于存储任意数目、任意类型的数据集合。 2.列表是内置可变序列&#xff0c;是包含多个元素的有序连续的内存空间。列表的标准语法格式&#xff1a;a[10,20,30,40]其中&#xff0c;10,20,30,40这些称为&#xff1a;列表a的元素。 3.…

2024年“华为杯”研赛第二十一届中国研究生数学建模竞赛解题思路|完整代码论文集合

我是Tina表姐&#xff0c;毕业于中国人民大学&#xff0c;对数学建模的热爱让我在这一领域深耕多年。我的建模思路已经帮助了百余位学习者和参赛者在数学建模的道路上取得了显著的进步和成就。现在&#xff0c;我将这份宝贵的经验和知识凝练成一份全面的解题思路与代码论文集合…

尚硅谷javaweb笔记

1、基本概念 1.1、前言 web开发&#xff1a; web&#xff0c;网页的意思&#xff0c;www.baidu.com 静态web html,css 提供给所有人看的数据始终不会发生变化&#xff01; 动态web 淘宝&#xff0c;几乎是所有的网站&#xff1b; 提供给所有人看的数据始终会发生变化&…

xxl-job demo下载部署测试

0.简要介绍 XXL-JOB是一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线&#xff0c;开箱即用。 1.下载 官网地址 gitee 2.准备 安装mysql&#xff0c;并在数据库中导入xxl-job必须的表&#…

利士策分享,周末时光:一场自我充实的精致规划

利士策分享&#xff0c;周末时光&#xff1a;一场自我充实的精致规划 在这个快节奏的生活中&#xff0c;周末仿佛是我们心灵的避风港&#xff0c;是忙碌一周后的温柔慰藉。如何充分利用这宝贵的48小时&#xff0c;让身心得到真正的放松与成长&#xff0c;成为了许多人探索的课…

IBM Spectrum LSF 用户基础

获取 IBM Spectrum LSF 工作负载管理概念和操作的概述。 1、IBM Spectrum LSF 概述 LSF 如何满足您的作业需求并找到运行该作业的最佳资源。 - IBM Spectrum LSF IBM Spectrum LSF (“LSF” &#xff0c;简称为负载共享设施) 软件是业界领先的企业级软件。 LSF 在现有异构 I…

Day69补 前后端分离思想

ajax前后端分离 前后端分离处理&#xff1a;前端------&#xff08;数据&#xff09;-----服务端----&#xff08;数据&#xff09;-----前端-----动态改变页面的内容 1.json 1、JSON&#xff1a;由于JSON易读以及纯文本格式的特性&#xff0c;可以非常容易地与其他程序进行沟通…