news 2026/8/28 5:12:12

高频必考!差分数组:批量区间更新如何做到 O(1) 一条?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
高频必考!差分数组:批量区间更新如何做到 O(1) 一条?

LeetCode 1109「航班预订统计」,场景真实得不像算法题:

你收到2万条预订记录,每条都是“从第a天到第b天,每天加c个座位”。
要你算出每一天的总座位数。

大多数人第一反应:

forfirst, last, seatsinbookings:
fordayinrange(first, last+1):
ans[day] += seats

「然后 TLE(超时)了。」
2万条记录 × 平均1万天 = 2亿次加法,不超时才怪。

「但差分数组告诉你:每条区间更新,只需要改两个数。」


📦 题目速览(30 秒读懂)

n个航班(编号 1~n),给你m条预订记录[first, last, seats],表示从firstlast的每个航班都增加seats个座位。
返回每个航班最终的座位总数。

「示例:」

输入:bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5 输出:[10, 55, 45, 25, 25]

「约束:」n和m都 ≤ 2×10⁴,暴力O(n*m)必挂。


🧠 核心思路:区间更新 = 开头 + 关水龙头,最后前缀和还原

暴力到底慢在哪里?

每条记录要遍历它覆盖的所有航班,区间越长越慢。而且多条记录之间相互独立,无法复用中间结果。

优化的数学本质——差分数组

区间[first, last]统一加seats,等价于:

  • first处“开始加” →diff[first] += seats
  • last+1处“停止加” →diff[last+1] -= seats

这就像一排水龙头:

  • 你在位置1打开阀门(流量 +10)
  • 在位置3关掉阀门(流量 -10)
  • 那么位置1~2都流了10,位置3及以后不流

「最后对整个diff做一次前缀和」,就能还原出每个位置的最终值。

「每条记录O(1),总共O(m),还原O(n),总复杂度O(m+n)。」


🖼️ 图解全过程(一眼就懂)

bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5为例:

「Step 1:差分数组初始全0」

索引0123456
diff0000000

「Step 2:处理每条记录(只改两个位置)」

预订操作diff 变化
[1,2,10]diff[1]+=10, diff[3]-=10[0,10,0,-10,0,0,0]
[2,3,20]diff[2]+=20, diff[4]-=20[0,10,20,-10,-20,0,0]
[2,5,25]diff[2]+=25, diff[6]-=25[0,10,45,-10,-20,0,-25]

「Step 3:前缀和还原(从左到右累加)」

航班 i累加过程结果
1total = 0 + 10「10」
2total = 10 + 45「55」
3total = 55 + (-10)「45」
4total = 45 + (-20)「25」
5total = 25 + 0「25」

最终:[10, 55, 45, 25, 25]

看到了吗?「无论区间多长,每条记录只动了两个数。」


💻 代码实现(Python + Java,附防坑版)

Python 版

classSolution:
defcorpFlightBookings(self, bookings: List[List[int]], n: int)-> List[int]:
# 多开 2 个位置,防止 last+1 越界
diff = [0] * (n +2)

forfirst, last, seatsinbookings:
diff[first] += seats
diff[last +1] -= seats

# 前缀和还原
ans = [0] * n
total =0
foriinrange(1, n +1):
total += diff[i]
ans[i -1] = total
returnans

Java 版

classSolution{
publicint[] corpFlightBookings(int[][] bookings,intn) {
int[] diff =newint[n +2];// 多开 2 位防越界

for(int[] b : bookings) {
diff[b[0]] += b[2];
diff[b[1] +1] -= b[2];
}

int[] ans =newint[n];
inttotal =0;
for(inti =1; i <= n; i++) {
total += diff[i];
ans[i -1] = total;
}
returnans;
}
}

⚠️「致命坑(必看)」

  • diff长度必须是n + 2,因为当last = n时,diff[n+1]会被访问。少开一位会数组越界。
  • 还原时循环从1到n,对应航班编号,而ans下标是0到n-1。

⏱️ 复杂度分析(面试必问)

  • 「处理预订」:O(m),每条O(1)
  • 「前缀和还原」:O(n)
  • 「总时间」:O(m + n),暴力是O(m × n)
  • 「空间」:O(n)(差分数组)

当m = n = 2×10⁴时,差分数组4×10⁴次操作 vs 暴力4×10⁸次,「差距1万倍」


🚀 举一反三:4 道高频变种题,一套框架通吃

题目差异点应对策略
「LeetCode 1094. 拼车」区间上下车,判断是否超载差分记录每站人数变化,还原后检查是否超过容量
「LeetCode 370. 区间加法」(会员题)纯差分模板直接套模板,改两个位置 + 前缀和
「LeetCode 1854. 人口最多的年份」出生-死亡区间,找人口峰值年差分记录每年人口变化,还原后找最大值
「LeetCode 798. 得分最高的最小轮调」(进阶)区间加分,求最大得分索引差分记录每个轮调位置的变化量

💬 面试追问模拟(提前准备,惊艳全场)

「Q1:差分数组和前缀和到底是什么关系?」

它们互为逆运算。

  • 原数组 → 差分数组(相邻差):diff[i] = nums[i] - nums[i-1]
  • 差分数组 → 原数组(前缀和):nums[i] = nums[i-1] + diff[i]

前缀和擅长“频繁区间查询”,差分数组擅长“频繁区间更新”,它们是同一枚硬币的两面。

「Q2:如果既有区间更新,又有区间查询,差分数组还够用吗?」

不够。差分数组只支持“最后统一查询”,如果更新和查询交替频繁,需要「树状数组(Fenwick Tree)「或」线段树」,它们支持 O(log n) 的区间更新 + 区间查询。

「Q3:差分数组能处理二维区间更新吗?(比如子矩阵全部 +v)」

可以。二维差分用容斥原理:
diff[x1][y1] += vdiff[x2+1][y1] -= vdiff[x1][y2+1] -= vdiff[x2+1][y2+1] += v
最后对每一行做前缀和,再对每一列做前缀和还原。


🧩 实战小技巧(刷题党必备)

  • 「口诀」:区间更新,左加右减;前缀还原,一路累加。
  • 「模板」:凡是“给区间加同一个值,最后求每个位置的值”,直接用差分数组。
  • 「空间优化」:如果不需要保留原始差分数组,可以直接在答案数组上做差分(原地操作),节省O(n)空间。

📈 实际应用场景(不止是刷题)

  • 「酒店/航班预订系统」:批量统计各日期的房间/座位预订量
  • 「会议室调度」:统计各时间段会议室占用数
  • 「交通流量分析」:统计各路段在某时段内的车流量
  • 「游戏经验值分配」:给某等级区间的玩家批量发放经验
  • 「工资/税务计算」:某收入区间的税率批量调整

🎁 今日思考题

如果bookings中既有“加座位”也有“退座位”(负值),差分数组需要改什么?
「提示」:完全不用改!seats可以为负数,diff[first] += seatsdiff[last+1] -= seats逻辑完全通用。

那如果每条记录不是“区间统一加”,而是“区间统一赋值为某个值”,差分数组还能用吗?欢迎评论区讨论 🧠

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 5:11:47

C函数_函数调用表达式

什么是函数调用表达式&#xff1f;函数调用表达式的格式是&#xff1a;函数名(参数列表)它的含义是&#xff1a;调用一个函数&#xff0c;并产生一个值——这个值就是函数的返回值。所以函数调用表达式本身是有"值"的&#xff0c;它的值就是函数 return 回来的那个东…

作者头像 李华
网站建设 2026/8/28 5:10:51

混合LoRA专家路由:不确定性不够,信息价值才是关键

刚接触 LoRA 和 MoE 路由的人&#xff0c;往往先被一个问题卡住&#xff1a;手头已经有好几个训练好的 LoRA 专家&#xff0c;系统不知道当前请求该交给谁。于是大家会想到让路由器看不确定性&#xff0c;也就是“哪个模型更犹豫就避开哪个”。但这个思路往往只能帮你排除错误答…

作者头像 李华
网站建设 2026/8/28 5:10:45

Zig Io.Threaded:用线程池封装阻塞I/O的设计与取舍

Zig 的 Io.Threaded 是我翻标准库时觉得最值得停下来看一遍的设计之一。它解决的是很具体的问题&#xff1a;你想在 Zig 里写看起来正常的同步文件读写&#xff0c;又不想让主线程被一次慢盘、一次网络请求卡住。Io.Threaded 的做法&#xff0c;是把所有会阻塞的 I/O 操作丢给线…

作者头像 李华
网站建设 2026/8/28 5:09:13

蓝桥杯国赛填空题复盘:从暴力枚举到数学优化与边界处理

1. 项目概述&#xff1a;为什么我们需要复盘2020年蓝桥杯国赛填空题&#xff1f;如果你是参加过蓝桥杯&#xff0c;或者正在备赛的选手&#xff0c;看到“2020年蓝桥杯B组国赛填空题整理”这个标题&#xff0c;大概会心一笑。这玩意儿&#xff0c;懂的都懂。它不像那些动辄几百…

作者头像 李华
网站建设 2026/8/28 5:08:15

Shopee Client秋招笔试复盘:从网络协议到MCP的客户端全链路考点

2024 年秋招&#xff0c;我投的是 Shopee 的 Client 提前批。说句实话&#xff0c;看到题目之前&#xff0c;我以为“Client 岗”的笔试重点会是界面框架、组件化、状态管理或者渲染优化这类东西。真正坐到在线笔试页面里我才发现&#xff0c;这套题更看重的是一个客户端工程师…

作者头像 李华
网站建设 2026/8/28 5:05:46

氢燃料电池无人机:M600改装两小时续航全解析

上周在南方一个无人机测试场&#xff0c;我抬头盯着一台灰白相间的DJI M600在头顶一圈接一圈地绕&#xff0c;地面站上的剩余氢压读数稳稳往下走。同一片空域的参照组是一台装电池的六轴&#xff0c;飞了四十多分钟就被飞手叫下来换电&#xff0c;而氢动力那台已经滞空一小时二…

作者头像 李华