前缀和与差分(二维)

news2024/11/16 2:29:20

二维前缀和

下面是一个二维数组,我们要求(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;          // 左上角增加val
    d[x2 + 1][y1] -= val;      // 下方减去val
    d[x1][y2 + 1] -= val;      // 右侧减去val
    d[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)增加3
    add(1, 1, 2, 2, -1); // 在区域(1,1)到(2,2)减少1
    
    // printD(); // 如果想调试差分数组d的状态,可以取消注释这一行
    
    pre_sum(); // 计算前缀和并更新矩阵g
    print();   // 输出更新后的矩阵g
    
    return 0; // 程序结束
}

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

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

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

相关文章

华为---代理ARP工作过程示例分析

目录 1. 示例场景 2. 基本配置 3. 配置代码 4. 测试验证 5. 抓包分析 5.1 在代理ARP环境下PC1和PC2通信分析 5.2 取消代理ARP环境下PC1和PC2通信分析 【1】取消R1路由器GE 0/0/1端口ARP代理 【2】取消R2路由器GE 0/0/1端口ARP代理 1. 示例场景 如上图所示&#xff0c;…

Python 中的方法解析顺序(MRO)

在 Python 中&#xff0c;MRO&#xff08;Method Resolution Order&#xff0c;方法解析顺序&#xff09;是指类继承体系中&#xff0c;Python 如何确定在调用方法时的解析顺序。MRO 决定了在多继承环境下&#xff0c;Python 如何寻找方法或属性&#xff0c;即它会根据一定规则…

Ceph 基本架构(一)

Ceph架构图 Ceph整体组成 Ceph 是一个开源的分布式存储系统&#xff0c;设计用于提供优秀的性能、可靠性和可扩展性。Ceph 的架构主要由几个核心组件构成&#xff0c;每个组件都有特定的功能&#xff0c;共同协作以实现高可用性和数据的一致性。 以下是 Ceph 的整体架构及其…

【PyTorch】autograd与逻辑回归

autograd – 自动求导系统 torch.autograd autograd torch.autograd.backward 功能&#xff1a;自动求取梯度 tensor&#xff1a;用于求导的张量&#xff0c;如lossretain_graph&#xff1a;保存计算图create_graph&#xff1a;创建导数计算图&#xff0c;用于高阶求导gra…

mac安装JetBtains全家桶新版本时报错:Cannot start the IDE

mac安装JetBtains全家桶新版本时报错&#xff1a;Cannot start the IDE 前言报错信息解决方法 前言 作者使用的是Mac电脑&#xff0c;最近想要更新JetBrains相关工具的软件版本&#xff0c;但是在安装时突然报错&#xff0c;导致安装失败&#xff0c;现在将报错信息以及解决方…

API应用安全风险倍增,F5助企业赢得关键安全挑战

如今&#xff0c;API应用安全的重要性与日俱增&#xff0c;但其复杂性也达到前所未有的程度。F5公司在亚太地区发布全新研究报告《2024策略洞察&#xff1a;亚太地区API安全报告》&#xff08;以下简称为“报告”&#xff09;&#xff0c;指出亚太地区企业正愈加依赖基于人工智…

Linux 进程2

环境变量 再Linux操作系统中一切皆文件&#xff0c;这个环境变量自然也是一个文件&#xff0c;它的作用是辅助我们使用操作系统还可以辨识我们是什么用户(一般用户&#xff0c;root用户)。 env是读取完整环境变量的指令&#xff0c;里面记录了许多我登录操作系统所用的用户的信…

一文说清楚ETL与Kafka如何实现集成

ETL与Kafka为何需要集成? 随着企业对实时流数据的处理要求越来越高&#xff0c;很多企业都把实时流数(日志、实时CDC采集数据、设备数据…)先推入到kafka中&#xff0c;再通过ETL对kafka中的数据进行消费通过ETL强大的数据的转换、清洗功能来进行数据的集成与分发。 实时数据…

table表格,让thead固定,tbody内容滚动,关键是都对齐的纯css写法

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f…

地信、测绘、遥感、地质相关岗位招聘汇总

3s等相关专业25秋招&提前批招聘信息 该岗位信息表&#xff0c;覆盖全国各大省市&#xff0c;招聘岗位主要针对地信、测绘、地质、遥感、城规等专业。 1800WebGIS开发岗位汇总表 该信息表&#xff0c;主要是WebGIS开发岗为主&#xff0c;岗位要求熟悉熟悉Openlayers&#…

【C++篇】~类和对象(中)

类和对象&#xff08;中&#xff09; 1.类的默认成员函数​ 默认成员函数就是用户没有显式实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数。一个类&#xff0c;我们不写的情况下编译器会默认生成以下6个默认成员函数&#xff0c;需要注意的是这6个中最重要的是前…

YOLOv8改进系列,YOLOv8替换主干网络为PP-HGNetV2(百度飞桨视觉团队自研,助力涨点)

摘要 PP-HGNetV2(High Performance GPU Network V2) 是百度飞桨视觉团队自研的 PP-HGNet 的下一代版本,其在 PP-HGNet 的基础上,做了进一步优化和改进,最终在 NVIDIA GPU 设备上,将 “Accuracy-Latency Balance” 做到了极致,精度大幅超过了其他同样推理速度的模型。其在…

远程桌面连接工具Microsoft Remote Desktop Beta for Mac

Microsoft Remote Desktop Beta for Mac 是一款功能强大的远程桌面连接工具&#xff0c;具有以下功能特点&#xff1a; 软件下载地址 跨平台连接&#xff1a; 允许 Mac 用户轻松连接到运行 Windows 操作系统的计算机&#xff0c;打破了操作系统的界限&#xff0c;无论这些 Wi…

什么是HTTP DDOS,如何防护

在当今高度互联的网络世界中&#xff0c;网络安全威胁日益严峻&#xff0c;其中HTTP DDoS&#xff08;Distributed Denial of Service&#xff0c;分布式拒绝服务&#xff09;攻击作为一种常见的网络攻击手段&#xff0c;给企业和个人用户带来了巨大的挑战。今天我们就来详细介…

计算机四级-计算机网络

一、基础知识 1.对计算机网络发展具有重要影响的广域网是&#xff1a;ARPANET 随机争用型的介质访问控制方法起源于&#xff1a;ALOHANET 2.计算机网络发展阶段&#xff1a; A&#xff09;第一阶段的主要成果是计算机技术与通信技术的结合 B&#xff09;第二阶段的主要成果…

ZYNQ FPGA自学笔记~操作PLL

一 时钟缓冲器、管理和路由 垂直时钟中心&#xff08;clock backbone&#xff09;将设备分为相邻的左侧和右侧区域&#xff0c;水平中心线将设备分为顶部和底部两侧。clock backbone中的资源镜像到水平相邻区域的两侧&#xff0c;从而将某些时钟资源扩展到水平相邻区域。BUFG不…

一、RTOS入门

目录 一、裸机与RTOS介绍 1、裸机 2、 RTOS 二、FreeRTOS简介 1、FreeRTOS 特点 2、关于FreeRTOS学习资料 一、裸机与RTOS介绍 1、裸机 简介&#xff1a;裸机又称为前后台系统&#xff0c;前台系统指的中断服务函数&#xff0c;后台系统指的大循环&#xff08;While循环…

基于PHP的新闻管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于phpMySQL的新闻管理系统。…

数据结构—(java)反射,枚举,lambda表达式

文章目录 反射反射的定义&#xff1a;反射相关的类&#xff1a;反射相关的方法&#xff1a;反射示例&#xff1a;获取Class类对象创建指定类的对象反射私有属性&#xff1a;反射私有方法&#xff1a;反射私有的构造方法 枚举枚举的意义枚举类的实现枚举类的使用&#xff1a;Enu…

JVM面试知识点手册

第一部分&#xff1a;JVM 概述 1.1 JVM 简介 Java Virtual Machine&#xff08;JVM&#xff09; 是 Java 语言的核心组件&#xff0c;负责将 Java 程序编译后的字节码&#xff08;bytecode&#xff09;转换为机器指令&#xff0c;并在目标机器上执行。JVM 提供了硬件和操作系…