前缀和题目:航班预订统计

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:航班预订统计

出处: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} 1n2×104
  • 1 ≤ bookings.length ≤ 2 × 10 4 \texttt{1} \le \texttt{bookings.length} \le \texttt{2} \times \texttt{10}^\texttt{4} 1bookings.length2×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} 1firstilastin
  • 1 ≤ seats i ≤ 10 4 \texttt{1} \le \texttt{seats}_\texttt{i} \le \texttt{10}^\texttt{4} 1seatsi104

解法

思路和算法

由于题目中给的航班编号范围是 1 1 1 n n n,答案数组的下标范围是 0 0 0 n − 1 n - 1 n1,因此需要将数组 bookings \textit{bookings} bookings 中的每个预订的开始航班和结束航班分别减 1 1 1 转换成答案数组的下标。

最直观的做法是对于每个预订更新航班区间中的所有航班的座位数,最坏情况下每个预订需要 O ( n ) O(n) O(n) 的时间更新航班的座位数,该时间复杂度过高,需要优化。

为了降低更新航班座位数的时间复杂度,需要使用差分数组。定义差分数组 diffs \textit{diffs} diffs,对于 0 ≤ i < n 0 \le i < n 0i<n diffs [ i ] = answer [ i ] − answer [ i − 1 ] \textit{diffs}[i] = \textit{answer}[i] - \textit{answer}[i - 1] diffs[i]=answer[i]answer[i1],这里规定 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[first1] 增加 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=n1 时, 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)。注意返回值不计入空间复杂度。