数据结构与算法-差分数组及应用

差分数组

差分数组: 其实差分数组是创建一个一个辅助数组,用来表示给定数组的变化,一般用来对数组进行区间修改的操作。

频繁操作数组区间的问题

假设我们要对一个数组进行区间操作。数组为 a = {10,10, 20,20,50,… 100}。数组数据比较多。

  1. 对数组的1~3项做加5操作(数组从0开始)

    遍历数组第1项~5项: a = {10,15,25,25,50,…}

  2. 对数组2~4项做加3操作

    遍历数组第2~4项: a = {10, 15, 28,28, 53,…}

    。。。。。。。。。。。。。。。。

我们发现大量的频繁的区间内操作每次都要对数据的指定位置进行遍历及运算,这样如果数组过大操作过于频繁会造成数组的响应时间过长,时间复杂度升高。

使用差分数组优化操作

创建差分数组

image-20240620104349178

所谓差分数组即数组中的每一项(除第0项)减去其前一项构成一个新的数组,此数组为差分数组。

在某个区间进行操作

先对区间[1,3]进行+5操作,我们发现差分数组diff[2] = 0, diff[3] = 10; diff[1] = 10+15(即区间的开始位置),diff[4]=30-5(即区间末尾+1)。

在对区间[2,4] 进行+8操作, 我们发现差分数组diff[3]=10, diff[4] = 25,diff[2]=0+8(区间起始位置2),diff[5]= 10-2=8(区间末尾加1)

image-20240620114446754

差分数组特性

特性1: 给区间[m, n]进行K数据操作

由图我们可以看出每次查分数组 a[start, end] 的操作数组, 从 m+1~n 数据不会发生变化,变化的只是a[m]和a[n+1]位置,且m位置值为原a[m]+K, a[n+1]-K, K值是区间内的每个数组元素的操作数据。

对a[m]+K,则对应的需要 a[n+1]-K

也就是说在差分数组中只有第m项和第n+1项的数据会发生变化(前提: 需要在区间内操作的数据相同)。

特性2: 原数组的每个数据值和差分数组的关系

a[n] = diff(Sum(n-1)) + diff[n]; 原数组当前数据 = 差分数组前项和+ 差分数组当前项

image-20240620162956291

a[1] = diff[0] + diff[1] = diff(Sum(0))+diff[1]= 0 + 15 = 15 = a[0] + diff[1];

a[2] = diff[0] + diff[1] + diff[2] =diff(Sum(1))+diff[2]= 0 + 15+8 = 23 = a[1] + diff[2];

a[3] = diff(Sum(2)) + diff[3] = 23 + 10 = a[2] + diff[3];

:

a[n] = diff(Sum(n-1)) + diff[n] = a[n-1] + diff[n]

差分数组使用

定义一个初始数组:int[] source = {0, 0, 0, 0, 0, 0, 0};

image-20240620172150139

获取差分数组

定义差分数组: int[] diff = new int[source.length];

image-20240620172202301

public static void diffExecute(int[] diff, int[] source) {
    for (int i = 1; i < source.length; i++) {
        diff[i] = source[i] - source[i - 1];
    }
}

区间[1,2]+10操作

在区间[1,2]中每一个数据+10,原数组变化为:

image-20240620172409924

  for (int i = 1; i <= 2; i++) source[i] += 10;

差分数组根据性质1: 只有[m,n]m位置和n+1位置会有数据改动。重构差分数组

image-20240620173648198

public static void diffx(int[] diff, int m, int n, int k) {
    diff[m] += k;  //区间起始点
    if (n < diff.length - 1) {
        diff[n + 1] -= k; //区间终止点的下一个位置
    }
}

区间[2,3]做+20操作

在区间[2,3]中每一个数据+20,原数组变化为:

image-20240620173010921

  for (int i = 1; i <= 2; i++) source[i] += 20;

差分数组变化,

image-20240620173703966

区间[2,5]做+25操作

在区间[2,3]中每一个数据+25,原数组变化为:

image-20240620173401060

  for (int i = 2; i <=5; i++) source[i] += 25;

差分数组变化

image-20240620173722908

由差分数组还原原数组计算后结果

原数组经过了[1,2]区间+10,[2,3]区间+20和[2,5]区间+25操作;我们同时也记录了差分数组的变化结果。接下来使用差分数组反推原数组的结果。此处我们使用差分数组的第2个特性: 当前项=前项和+当前项, diff[i] = diff[i-1] +diff[i]; 为程序清晰,我定义sum来记录前项和(可以自行简化代码)。

image-20240620174804995

int sum = diff[0];
for (int i = 1; i < dest.length; i++) {
    sum = sum + diff[i];
    diff[i] = sum;
}

我们对比一下原始数据经过一系列变化后,发现和最后的结果是一致的。

image-20240620175103609

经典问题

1109. 航班预订统计 - 力扣(LeetCode)

image-20240620175238399

解题思路使用差分数组

由于在某个区间内会频繁进行数据的操作,可以创建一个差分辅助数组利用性质2,只操作m项和n+1项(m,为区间起始位置,n为区间终止位置的下一个位置)。

public int[] corpFlightBookings(int[][] bookings, int n) {
    int[] diff = new int[n];

    for (int i = 0; i < bookings.length; i++) {  //遍历二维数组找到区间和要修改的值
        int[] booking = bookings[i];
        int val = booking[2];
        int start = booking[0];
        int end = booking[1];
        
        diff[start - 1] += val; //start-1是日期从1开始,我们的数组从0开始,利用差分数组性质1:记录起始位置增量

        if (end < n) {
            diff[end] -= val;   //性质1: 和起始位置进行相反操作,不用+1是因为起始位置左移了一个位置。
        }
    }

    /*
     *  差分数组性质2:  前项和+当前项
     */
    for (int i = 1; i < diff.length; i++) { 
        diff[i] = diff[i] + diff[i - 1];
    }

    return diff;

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

羊大师:培养儿童配得感,从自我认知开始

在儿童的成长过程中&#xff0c;配得感的培养是至关重要的。配得感&#xff0c;即孩子认为自己值得拥有美好事物和得到他人关爱的一种心理状态&#xff0c;是孩子自信心和自尊心的基石。而自我认知&#xff0c;则是培养配得感的第一步。 我们要引导孩子正确地认识自己。每个孩子…

vant组件 顶部下拉刷新和页面底部下拉获取数据

1.html部分&#xff08;顶部tab切换无&#xff0c;只有主体list部分&#xff09; <div class"yd" ><!-- yd端 --><van-pull-refresh v-model"refreshing" refresh"onRefresh"><van-listv-model"ydloading":finis…

【SpringCloud】Eureka的简单使用

本文使用的是jdk17&#xff0c;mysql8。 以下用两个服务做演示&#xff1a; 订单服务&#xff1a;提供订单ID&#xff0c;获取订单详细信息。 商品服务&#xff1a;提供商品ID&#xff0c;获取商品详细信息。 对于上篇http://t.csdnimg.cn/vcWpo 订单服务调用商品服务的时候&a…

Markdown 生成 Epub (Typora + pandoc)

文章目录 一、安装 pandoc二、Typora pandoc 导出 Pandoc 文件三、看看效果 一、安装 pandoc macOS 上使用 brew 安装 brew install pandoc其他系统可见&#xff1a;https://pandoc.org/installing.html 安装成功后查看版本 pandoc --version$ pandoc --version pandoc 2.1…

PS选不了颜色和路径描边?PS不知为何才能描边任意路径,这个办法让你秒懂

在选中路径的情况下&#xff0c;按图下操作&#xff0c;即可制作路径&#xff08;不会让你选不了颜色和路径描边&#xff09;

ArcGIS查找相同图斑、删除重复图斑

​ 点击下方全系列课程学习 点击学习—>ArcGIS全系列实战视频教程——9个单一课程组合系列直播回放 点击学习——>遥感影像综合处理4大遥感软件ArcGISENVIErdaseCognition 这次是上次 今天分享一下&#xff0c;很重要却被大家忽略的两个工具 这两个工具不仅可以找出属性…

聊一聊 Monitor.Wait 和 Pluse 的底层玩法

一&#xff1a;背景 1. 讲故事 在dump分析的过程中经常会看到很多线程卡在Monitor.Wait方法上&#xff0c;曾经也有不少人问我为什么用 !syncblk 看不到 Monitor.Wait 上的锁信息&#xff0c;刚好昨天有时间我就来研究一下。 二&#xff1a;Monitor.Wait 底层怎么玩的 1. 案…

【启明智显产品分享】Model3工业级HMI芯片详解系列专题(三):安全、稳定、高防护

芯片作为电子设备的核心部件&#xff0c;&#xff0c;根据不同的应用领域被分为不同等级。工业级芯片适用于工业自动化、控制系统和仪器仪表等领域&#xff0c;对芯片的安全、稳定、防护能力等等有着较高的要求。这些芯片往往需要具备更宽的工业温度范围&#xff0c;能够在更恶…

阿里云服务器提醒漏洞要不要打补丁?

我们自己用的电脑一旦发现漏洞&#xff0c;往往是第一时间进行打补丁重启等等&#xff0c;但是作为服务器而言&#xff0c;往往没有这个习惯&#xff0c;为什么&#xff1f;因为害怕服务器打补丁以后&#xff0c;重启后出现打不开的情况&#xff0c;毕竟稳定的运行似乎在这种情…

最新版Cisco Packet Tracer思科模拟器Windows版本64位下载

Cisco Packet Tracer是思科公司推出的一款网络仿真工具&#xff0c;主要用于网络教学、培训和实验。它提供了一个真实的网络环境模拟平台&#xff0c;让用户可以设计、构建和调试网络&#xff0c;以及进行实时互动&#xff0c;从而帮助用户理解和实践网络技术。 通过 Cisco Pa…

稳定运行 极限生存│美创韧性运行安全体系正式发布

在全面数字化的今天&#xff0c;时刻运转的业务、实时流转的数据&#xff0c;已成为组织生产经营不可或缺的基石。然而&#xff0c;云化、国产化深入推进&#xff0c;数据快速增长&#xff0c;数据库、应用、中间件等信息化资产日益散杂多乱&#xff0c;给组织的运行安全带来更…

【docker】adoptopenjdk/openjdk8-openj9:alpine-slim了解

adoptopenjdk/openjdk8-openj9:alpine-slim 是一个 Docker 镜像的标签&#xff0c;它指的是一个特定的软件包&#xff0c;用于在容器化环境中运行 Java 应用程序。 镜像相关的网站和资源&#xff1a; AdoptOpenJDK 官方网站 - AdoptOpenJDK 这是 AdoptOpenJDK 项目的官方网站&…

UV胶带和UV胶水的应用场景有哪些不同吗?

UV胶带和UV胶水的应用场景有哪些不同吗? UV胶带和UV胶水的应用场景确实存在不同之处&#xff0c;以下是详细的比较和归纳&#xff1a; 一&#xff1a;按使用场景来看&#xff1a; UV胶带的应用场景&#xff1a; 包装行业&#xff1a;UV胶带在包装行业中常用于食品包装、药…

AMD vs NVIDIA:渲染领域的显卡之争

在数字创意与设计的世界里&#xff0c;显卡作为图形处理的核心&#xff0c;其性能与兼容性直接关系到创作者的工作效率与作品质量。AMD与NVIDIA&#xff0c;作为两大显卡巨头&#xff0c;各自在渲染领域拥有独特的技术与优势。那么&#xff0c;针对渲染而言&#xff0c;哪种显卡…

springboot vue 开源 会员收银系统 (7) 收银台的完善 新增开卡 结算

前言 完整版演示 开发版演示 在前面的开发中&#xff0c;我们成功完成了商品分类和商品信息的搭建&#xff0c;开发了收银台基础。现在&#xff0c;我们将进一步完善收银台的功能&#xff0c;添加开卡和结算功能&#xff0c;并在后台实现会员卡的创建和订单保存。同时&#xff…

2024-06月 | 维信金科 | 风控数据岗位推荐,高收入岗位来袭!

今日推荐岗位&#xff1a;策略分析经理/分析专家、贷前、中策略分析、风控模型分析。 风控部门是金融业务的核心部门&#xff0c;而从事风控行业的人即称之为风险管理者。是大脑&#xff0c;是最最最重要的部门之一。今日推荐岗位的核心技能分布如下&#xff1a; 简历发送方式…

一名女DBA的感谢信,到底发生了什么?

昨日我们收到这样一通来电 “早上九点刚上班便收到业务投诉电话&#xff0c;系统卡顿&#xff0c;接口失败率大增&#xff0c;怀疑数据库问题。打开运维平台发现是国产库&#xff0c;生无可恋&#xff0c;第一次生产环境遇到国产库性能问题&#xff0c;没什么排查经验&#xf…

Jetpack Compose 中的嵌套 LazyColumn

Jetpack Compose 中的嵌套 LazyColumn 在展示一组元素时&#xff0c;我们通常会使用 Column 和 Row。然而&#xff0c;当涉及到长列表的显示时&#xff0c;我们使用 LazyColumn、LazyRow 或 LazyGrids&#xff0c;这些组件仅渲染屏幕上可见的项目&#xff0c;从而提高性能并减…

MYSQL 四、mysql进阶 4(索引的数据结构)

一、为什么使用索引 以及 索引的优缺点 1.为什么使用索引 索引是存储引擎用于快速找到数据记录的一种数据结构&#xff0c;就好比一本教科书的目录部分&#xff0c;通过目录中找到对应文章的页码&#xff0c;便可快速定位到需要的文章。Mysql中也是一样的道理&#xff0c;进行数…

DY-110DP低电压继电器 25-124V 嵌入式安装 约瑟JOSEF

系列型号 DY-110电压继电器&#xff1b;GY-110电压继电器&#xff1b; GDY-110电压继电器&#xff1b;DY-110/AC电压继电器&#xff1b; GY-110/AC电压继电器&#xff1b;GDY-110/AC电压继电器&#xff1b; DL-110电压继电器&#xff1b;GL-110电压继电器&#xff1b; DL-…