文章目录
- 题目
- 标题和出处
- 难度
- 题目描述
- 要求
- 示例
- 数据范围
- 解法
- 思路和算法
- 代码
- 复杂度分析
题目
标题和出处
标题:航班预订统计
出处:1109. 航班预订统计
难度
5 级
题目描述
要求
有 n \texttt{n} n 个航班,从 1 \texttt{1} 1 到 n \texttt{n} n 编号。
给定一个航班预订表的数组 bookings \texttt{bookings} bookings,其中 bookings[i] = [first i , last i , seats i ] \texttt{bookings[i] = [first}_\texttt{i}\texttt{, last}_\texttt{i}\texttt{, seats}_\texttt{i}\texttt{]} bookings[i] = [firsti, lasti, seatsi] 表示从 first i \texttt{first}_\texttt{i} firsti 到 last i \texttt{last}_\texttt{i} lasti(包含 first i \texttt{first}_\texttt{i} firsti 和 last i \texttt{last}_\texttt{i} lasti)的每个航班上预订了 seats i \texttt{seats}_\texttt{i} seatsi 个座位。
返回一个长度为 n \texttt{n} n 的数组 answer \texttt{answer} answer,其中 answer[i] \texttt{answer[i]} answer[i] 是第 i \texttt{i} i 个航班预订的座位总数。
示例
示例 1:
输入: bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5 \texttt{bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5} bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
输出: [10,55,45,25,25] \texttt{[10,55,45,25,25]} [10,55,45,25,25]
解释:
航班编号: 1 2 3 4 5 ~\texttt{~~~1~~~2~~~3~~~4~~~5} 1 2 3 4 5
预订记录 1 \texttt{1} 1: 10 10 \texttt{~10~~10} 10 10
预订记录 2 \texttt{2} 2: 20 20 \texttt{~~~~~20~~20} 20 20
预订记录 3 \texttt{3} 3: 25 25 25 25 \texttt{~~~~~25~~25~~25~~25} 25 25 25 25
总座位数: 10 55 45 25 25 ~\texttt{~~10~~55~~45~~25~~25} 10 55 45 25 25
因此, answer = [10,55,45,25,25] \texttt{answer = [10,55,45,25,25]} answer = [10,55,45,25,25]。
示例 2:
输入: bookings = [[1,2,10],[2,2,15]], n = 2 \texttt{bookings = [[1,2,10],[2,2,15]], n = 2} bookings = [[1,2,10],[2,2,15]], n = 2
输出: [10,25] \texttt{[10,25]} [10,25]
解释:
航班编号: 1 2 ~\texttt{~~1~~~2} 1 2
预订记录 1 \texttt{1} 1: 10 10 \texttt{10~~10} 10 10
预订记录 2 \texttt{2} 2: 15 \texttt{~~~~15} 15
总座位数: 10 25 ~\texttt{~10~~25} 10 25
因此, answer = [10,25] \texttt{answer = [10,25]} answer = [10,25]。
数据范围
- 1 ≤ n ≤ 2 × 10 4 \texttt{1} \le \texttt{n} \le \texttt{2} \times \texttt{10}^\texttt{4} 1≤n≤2×104
- 1 ≤ bookings.length ≤ 2 × 10 4 \texttt{1} \le \texttt{bookings.length} \le \texttt{2} \times \texttt{10}^\texttt{4} 1≤bookings.length≤2×104
- bookings[i].length = 3 \texttt{bookings[i].length} = \texttt{3} bookings[i].length=3
- 1 ≤ first i ≤ last i ≤ n \texttt{1} \le \texttt{first}_\texttt{i} \le \texttt{last}_\texttt{i} \le \texttt{n} 1≤firsti≤lasti≤n
- 1 ≤ seats i ≤ 10 4 \texttt{1} \le \texttt{seats}_\texttt{i} \le \texttt{10}^\texttt{4} 1≤seatsi≤104
解法
思路和算法
由于题目中给的航班编号范围是 1 1 1 到 n n n,答案数组的下标范围是 0 0 0 到 n − 1 n - 1 n−1,因此需要将数组 bookings \textit{bookings} bookings 中的每个预订的开始航班和结束航班分别减 1 1 1 转换成答案数组的下标。
最直观的做法是对于每个预订更新航班区间中的所有航班的座位数,最坏情况下每个预订需要 O ( n ) O(n) O(n) 的时间更新航班的座位数,该时间复杂度过高,需要优化。
为了降低更新航班座位数的时间复杂度,需要使用差分数组。定义差分数组 diffs \textit{diffs} diffs,对于 0 ≤ i < n 0 \le i < n 0≤i<n 有 diffs [ i ] = answer [ i ] − answer [ i − 1 ] \textit{diffs}[i] = \textit{answer}[i] - \textit{answer}[i - 1] diffs[i]=answer[i]−answer[i−1],这里规定 answer [ − 1 ] = 0 \textit{answer}[-1] = 0 answer[−1]=0,因此 diffs [ 0 ] = answer [ 0 ] \textit{diffs}[0] = \textit{answer}[0] diffs[0]=answer[0]。
对于预订 [ first , last , seats ] [\textit{first}, \textit{last}, \textit{seats}] [first,last,seats],其中 first \textit{first} first 和 last \textit{last} last 已经转换成答案数组的下标,需要将答案数组 answer \textit{answer} answer 的下标区间 [ first , last ] [\textit{first}, \textit{last}] [first,last] 中的每个元素值都增加 seats \textit{seats} seats,等价于 answer [ first ] − answer [ first − 1 ] \textit{answer}[\textit{first}] - \textit{answer}[\textit{first} - 1] answer[first]−answer[first−1] 增加 seats \textit{seats} seats 且 answer [ last + 1 ] − answer [ last ] \textit{answer}[\textit{last} + 1] - \textit{answer}[\textit{last}] answer[last+1]−answer[last] 减少 seats \textit{seats} seats,答案数组的其余相邻元素之间的差值都不变,因此可以将 diffs [ first ] \textit{diffs}[\textit{first}] diffs[first] 的值增加 seats \textit{seats} seats 和将 diffs [ last + 1 ] \textit{diffs}[\textit{last} + 1] diffs[last+1] 的值减少 seats \textit{seats} seats,即可表示区间中的元素值变化。特别地,当 last = n − 1 \textit{last} = n - 1 last=n−1 时, last + 1 \textit{last} + 1 last+1 超出数组下标范围,因此不更新 diffs [ last + 1 ] \textit{diffs}[\textit{last} + 1] diffs[last+1] 的值。使用差分数组,对于每个预订只需要 O ( 1 ) O(1) O(1) 的时间更新差分数组。
遍历所有预订之后,计算差分数组的前缀和数组,即为答案 answer \textit{answer} answer。
实现方面,由于 diffs [ 0 ] = answer [ 0 ] \textit{diffs}[0] = \textit{answer}[0] diffs[0]=answer[0] 且 answer \textit{answer} answer 是 diffs \textit{diffs} diffs 的前缀和数组,因此可以将 answer \textit{answer} answer 作为差分数组,最后对 answer \textit{answer} answer 计算前缀和并更新数组中的每个元素值,遍历结束之后的 answer \textit{answer} answer 即为答案。使用该实现方法,除了返回值以外不需要额外创建数组。
代码
class Solution {public int[] corpFlightBookings(int[][] bookings, int n) {int[] answer = new int[n];for (int[] booking : bookings) {int first = booking[0] - 1, last = booking[1] - 1, seats = booking[2];answer[first] += seats;if (last < n - 1) {answer[last + 1] -= seats;}}for (int i = 1; i < n; i++) {answer[i] += answer[i - 1];}return answer;}
}
复杂度分析
-
时间复杂度: O ( n + b ) O(n + b) O(n+b),其中 n n n 是航班数量, b b b 是数组 bookings \textit{bookings} bookings 的长度。需要遍历数组 bookings \textit{bookings} bookings 更新差分数组,每次更新的时间是 O ( 1 ) O(1) O(1),计算答案数组需要遍历差分数组一次计算前缀和,时间是 O ( n ) O(n) O(n),因此时间复杂度是 O ( n + b ) O(n + b) O(n+b)。
-
空间复杂度: O ( 1 ) O(1) O(1)。注意返回值不计入空间复杂度。