当前位置: 首页 > ds >正文

区间修改 - 差分

文章目录

  • 问题描述
  • 暴力解法
  • 差分数组优化
    • 核心思想
    • 区间修改的技巧
    • 代码实现
  • 总结

问题描述

最近在刷题的时候,遇到了一类区间修改的问题,刚开始用暴力法做,结果TLE了。后来学了差分数组这个技巧,解决的是区间修改问题,发现效率提升巨大。今天整理一下,分享给大家。
在这里插入图片描述

暴力解法

最直接的想法就是老老实实遍历区间,一个一个改:

public class BruteForce {public static void rangeUpdate(int[] arr, int left, int right, int val) {for (int i = left; i <= right; i++) {arr[i] += val;}}public static void main(String[] args) {int[] arr = {1, 2, 3, 4, 5};rangeUpdate(arr, 1, 3, 2);System.out.println("操作1后: " + Arrays.toString(arr));rangeUpdate(arr, 2, 4, -1);System.out.println("操作2后: " + Arrays.toString(arr));}
}

这种方法简单粗暴,但是效率不高: 时间复杂度:O(m*n),m是操作次数,n是数组长度。

差分数组优化

核心思想

差分数组的精髓在于:用差值来表示数组,把区间修改变成两个点的修改

什么意思呢?假设原数组是[1, 2, 3, 4, 5],它的差分数组是:

diff[0] = 1        // arr[0] = 1
diff[1] = 1        // arr[1] - arr[0] = 1
diff[2] = 1        // arr[2] - arr[1] = 1
diff[3] = 1        // arr[3] - arr[2] = 1
diff[4] = 1        // arr[4] - arr[3] = 1

神奇的地方来了:原数组就是差分数组的前缀和

arr[0] = diff[0] = 1
arr[1] = diff[0] + diff[1] = 1+1 = 2
arr[2] = diff[0] + diff[1] + diff[2] = 1+1+1 = 3
...

区间修改的技巧

要给区间[left, right]都加上val,只需要:

  1. diff[left] += val
  2. diff[right+1] -= val

为什么这样就行了?因为当我们计算前缀和还原数组时:

  • 从left开始,每个位置都会多加val
  • 从right+1开始,又会减掉val,抵消了

代码实现

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();long[] a = new long[n + 1];long[] diff = new long[n + 2];for (int i = 1; i <= n; i++) {a[i] = in.nextLong();diff[i] = a[i] - a[i - 1];}while (m-- > 0) {int l = in.nextInt();int r = in.nextInt();long k = in.nextLong();diff[l] += k;diff[r + 1] -= k;}for (int i = 1; i <= n; i++) {a[i] = a[i - 1] + diff[i];}for (int i = 1; i <= n; i++) {System.out.print(a[i] + " ");}}
}

总结

差分数组虽然听起来高大上,但本质就是一个很朴素的思想:用差值来描述变化,通过前缀和来还原状态。它的优势在于把O(n)的区间修改变成了O(1)的操作,当操作次数很多时,效率提升非常明显。

http://www.xdnf.cn/news/17716.html

相关文章:

  • Kubernetes部署apisix的理论与最佳实践(一)
  • npm install报错~[master] npm install npm error code ERESOLVE npm err
  • 大数据系统架构模式:驾驭海量数据的工程范式
  • RabbitMQ 消息转换器详解
  • 心理咨询|学生心理咨询评估系统|基于Springboot的学生心理咨询评估系统设计与实现(源码+数据库+文档)
  • 使用TextureView和MediaPlayer播放视频黑屏问题
  • AI模型服务接入WAF防火墙
  • 【C++】哈希表的实现(unordered_map和unordered_set的底层)
  • DDIA第五章:分布式数据复制中的一致性与冲突处理
  • 触想定制化工业一体机化身渔业预警终端,守望渔船安全
  • Spring Boot 菜单删除功能的实现与事务管理
  • 【前端基础】16、结构伪类(注:粗略说明)
  • 数据上云有什么好处?企业数据如何上云?
  • 基于FPGA的热电偶测温数据采集系统,替代NI的产品(一)FPGA 测温研究现状
  • 自由学习记录(81)
  • 【JAVA】使用系统音频设置播放音频
  • 零 shot 语义+在线闭环:深度学习让机器人学会“主动”
  • MySQL 数据操作全流程:创建、读取、更新与删除实战
  • 对比FRI 与 Ligero 证明大小
  • 怎么实现表征工程并强化模型的“事实性”“诚信性”
  • 深入解析大模型落地的四大核心技术:微调、提示词工程、多模态应用 及 企业级解决方案,结合代码示例、流程图、Prompt案例及技术图表,提供可落地的实践指南。
  • FreeRTOS学习:资源管理:互斥操作的本质
  • 腾讯云EdgeOne Pages深度使用指南
  • GPU指令集入门教程
  • 《 C Primer Plus》
  • 常用hook钩子函数
  • 快速了解DBSCAN算法
  • Vue.js设计于实现 - 响应式(三)
  • 音视频学习(五十二):ADTS
  • Graham 算法求二维凸包