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

前缀和 差分

差分和前缀和都是算法里边比较重要的知识点,不过学习的难度并不高,这篇文章会讲解相关的内容。

1. 前缀和怎么玩

1)一维前缀和

在该数之前,包括该数的所有数之和,有点类似高中学的数列的前n项和Sn。

2)二维前缀和

根据原数组生成sum数组,sum[i][j]表示从(0, 0)到(i, j)这个范围内的累加和

求法:依次求 左 + 上 - 左上 + 自己,再从左到右,从上到下生成

*往往补第0行、第0列来减少条件判断

【图解】

Q:如果要求某个范围内的累加和怎么办?

设求(a, b)到(c, d)的累加和,则累加和就是

sum[c][d] - sum[a-1][d] - sum[c][b-1] + sum[a-1][b-1]

根据sum数组的定义和下面的图解就非常清晰了

图解如下:

【练习】

有一道模版题,大家可以试着做做:链接

核心的思路就是二维前缀和,我的代码如下: 

class NumMatrix {
public:vector<vector<int>> sum;NumMatrix(vector<vector<int>>& matrix) {int m = matrix.size();int n = matrix[0].size();sum.resize(m + 1, vector<int>(n + 1));// 第0行、第0列空出来,减少判断for (int a = 0, b = 1; a < m; a++, b++)for (int c = 0, d = 1; c < n; c++, d++)sum[b][d] = matrix[a][c];// 求前缀和for (int i = 1; i <= m; i++)for (int j = 1; j <= n; j++)sum[i][j] += sum[i - 1][j] +sum[i][j - 1] - sum[i - 1][j - 1];}int sumRegion(int row1, int col1, int row2, int col2) {row2++;col2++;return sum[row2][col2] - sum[row2][col1]- sum[row1][col2] + sum[row1][col1];}
};

2. 差分怎么玩

前缀和是为了下面学习差分做铺垫的,那么差分是什么玩意呢?

一般来说,差分分为3种类型,分别是一维差分、二维差分、等差差分

1)一维差分

首先,来看一个例子:

给定一个开始全为0的数组(设大小为8),在指定下标范围进行加减操作,求多次操作后的数组

分别对2~5下标对应的数进行加3,1~3下标加2,4~6下标减2

当然,你也可以每个动作都循环一次,但是那样代码写得有点挫,而差分就是解决这样一类的问题的好方法。

【使用方式】

在每个动作的左位置下标做对应的操作,在右位置的下一个数进行逆操作,所有操作一遍后,用前缀和加工。

这是什么意思,说的是人话吗?🤔

比如,对2~5下标对应的数进行加3,那么就在2位置加3,在6位置减3;(此为一次操作)

对1~3位置加2,就对应着1位置加2,4位置减2;(第二次操作)

对4~6位置减2,对应4位置减2,7位置加2。(第三次操作)

最后进行前缀和加工(此步骤可以在多次操作后进行)

【图解】

【原理】

操作方式就是如上,原理也很简单,因为一开始全是0,那么在进行前缀和操作时就不会受到初始值的影响,只会由我们自己的操作控制。

而在第一个位置加了3,那么经过前缀和的操作就会让该位置及其后的位置都加了3,而因为在最右的位置在往后就不用操作了,那么就需要它的逆操作来抵消了。

【练习】

leetcode_1109航班预订

核心思路就是一维差分 + 前缀和加工,其实就相当于模版题了

参考代码:

class Solution {
public:vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {vector<int> sum(n + 2, 0);for(int i = 0; i < bookings.size(); i++){sum[bookings[i][0]] += bookings[i][2];sum[bookings[i][1] + 1] -= bookings[i][2];}vector<int> ans;for(int i = 1; i <= n; i++){sum[i] += sum[i - 1];ans.push_back(sum[i]);}return ans;}
};

2)二维差分

跟一维差分类似,也是在初始全为0的条件下,然后在给定两个坐标区间,进行加减操作,多次操作后,求变化后的数组

【使用方式】

设 (a, b) 到 (c, d) 的范围 + v

一次操作:  (a, b) + v 

(a, d+1) - v

(c+1, b) - v

(c+1, d+1) + v

···(多次操作)

最后要加工前缀和

其实原理跟一维差分是类似的,也是因为在前缀和的加工后,对于某个点的变化就成了一片区域的变化,而对于重叠的变化(减了2次)需要再处理

【图解】

【练习】

leetcode_2132贴邮票

核心:二维前缀和与二维差分的结合

思考逻辑:先不考虑邮票的重叠,直接把能贴的位置都贴上,其中判断能不能贴是根据区域前缀和是否为0,贴邮票二维差分的过程(对应四角处理),最后再前缀和加工

注意:此题要非常注意数组的范围,不然会越界

参考代码:链接(内含注释)

3)等差差分

这类问题相当考的较少,可以考虑先跳过

一般的问题描述是,一开始数组全为0,接下来有若干次(已知)操作,每次操作分别是在 l~r 范围上依次加上首项为s,末项为e,公差为d的等差数列,求多次操作后的数组

【使用方式】

arr[l] += s

arr[l + 1] += d - s

arr[r + 1] -= d + e

arr[r + 2] += e

多次操作后,再加工两次前缀和

【图解】

【练习】

luogu_P4231三步必杀

其实就是模板题,思路不难

注意数据量比较大,要用 long long

参考代码:链接

如果有问题可以在评论区一起讨论,对你有帮助的话不妨点个赞👍

相关文章:

  • 05 - 什么是路由协议
  • 数据结构—动态查找
  • 第十章 函数 (上)第一节-第九节
  • 宠物处方单子怎么开,宠物门诊处方管理软件教程
  • JVM 笔记
  • 常见的网络安全威胁和防护方法
  • C++——构造函数
  • Android使用ScrollView导致鼠标点击事件无效
  • LeetCode 热题 100 | 链表(上)
  • 解决Docker AList本地挂载失效的问题。
  • 免费电视TV盒子软件,好用的免费电视盒子软件大全,免费电视盒子APP大全,2024最新整理
  • 影院购票|电影院订票选座小程序|基于微信小程序的电影院购票系统设计与实现(源码+数据库+文档)
  • npm 以组织为单位发布依赖包(@username/package-name、@org-name/package-name)
  • 【全网最全】2024美赛ABCDEF题思路模型全解(后续会更新)
  • go语言标准库flag命令行参数解析
  • 【Linux系统编程】快速查找errno错误码信息
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • 4个实用的微服务测试策略
  • CentOS7 安装JDK
  • Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • Odoo domain写法及运用
  • Python连接Oracle
  • Xmanager 远程桌面 CentOS 7
  • 编写高质量JavaScript代码之并发
  • 不发不行!Netty集成文字图片聊天室外加TCP/IP软硬件通信
  • 模型微调
  • 普通函数和构造函数的区别
  • 前端面试总结(at, md)
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 使用docker-compose进行多节点部署
  • 通过git安装npm私有模块
  • 小李飞刀:SQL题目刷起来!
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 因为阿里,他们成了“杭漂”
  • 在Unity中实现一个简单的消息管理器
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • (day 12)JavaScript学习笔记(数组3)
  • (libusb) usb口自动刷新
  • (zt)最盛行的警世狂言(爆笑)
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • (一)基于IDEA的JAVA基础1
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]
  • .htaccess配置重写url引擎
  • .net CHARTING图表控件下载地址
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • .NET Framework 4.6.2改进了WPF和安全性
  • .NET 设计一套高性能的弱事件机制
  • .NET开源项目介绍及资源推荐:数据持久层