Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f2b0c30

Browse files
✨feat: Add 1109
1 parent 8aff918 commit f2b0c30

File tree

3 files changed

+202
-0
lines changed

3 files changed

+202
-0
lines changed

‎Index/差分.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
| 题目 | 题解 | 难度 | 推荐指数 |
22
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- |
33
| [995. K 连续位的最小翻转次数](https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/solution/po-su-tan-xin-jie-fa-yu-tan-xin-chai-fen-4lyy/) | 困难 | 🤩🤩🤩 |
4+
| [1109. 航班预订统计](https://leetcode-cn.com/problems/corporate-flight-bookings/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/corporate-flight-bookings/solution/gong-shui-san-xie-yi-ti-shuang-jie-chai-fm1ef/) | 中等 | 🤩🤩🤩🤩🤩 |
45

‎Index/线段树.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
| 题目 | 题解 | 难度 | 推荐指数 |
22
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- |
3+
| [1109. 航班预订统计](https://leetcode-cn.com/problems/corporate-flight-bookings/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/corporate-flight-bookings/solution/gong-shui-san-xie-yi-ti-shuang-jie-chai-fm1ef/) | 中等 | 🤩🤩🤩🤩🤩 |
34
| [1893. 检查是否区域内所有整数都被覆盖](https://leetcode-cn.com/problems/check-if-all-the-integers-in-a-range-are-covered/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/check-if-all-the-integers-in-a-range-are-covered/solution/gong-shui-san-xie-yi-ti-shuang-jie-mo-ni-j83x/) | 简单 | 🤩🤩🤩🤩 |
45

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[1109. 航班预订统计](https://leetcode-cn.com/problems/corporate-flight-bookings/solution/gong-shui-san-xie-yi-ti-shuang-jie-chai-fm1ef/)** ,难度为**中等**
4+
5+
Tag : 「区间求和问题」、「差分」、「线段树」
6+
7+
8+
9+
这里有 `n` 个航班,它们分别从 `1``n` 进行编号。
10+
11+
有一份航班预订表 `bookings`,表中第 `i` 条预订记录 $bookings[i] = [first_i, last_i, seats_i]$ 意味着在从 $first_i$ 到 $last_i$ (包含 $first_i$ 和 $last_i$ )的 每个航班 上预订了 $seats_i$ 个座位。
12+
13+
请你返回一个长度为 `n` 的数组 `answer`,其中 `answer[i]` 是航班 `i` 上预订的座位总数。
14+
15+
示例 1:
16+
```
17+
输入:bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
18+
19+
输出:[10,55,45,25,25]
20+
21+
解释:
22+
航班编号 1 2 3 4 5
23+
预订记录 1 : 10 10
24+
预订记录 2 : 20 20
25+
预订记录 3 : 25 25 25 25
26+
总座位数: 10 55 45 25 25
27+
因此,answer = [10,55,45,25,25]
28+
```
29+
示例 2:
30+
```
31+
输入:bookings = [[1,2,10],[2,2,15]], n = 2
32+
33+
输出:[10,25]
34+
35+
解释:
36+
航班编号 1 2
37+
预订记录 1 : 10 10
38+
预订记录 2 : 15
39+
总座位数: 10 25
40+
因此,answer = [10,25]
41+
```
42+
提示:
43+
* 1 <= n <= 2ドル * 10^4$
44+
* 1 <= bookings.length <= 2ドル * 10^4$
45+
* bookings[i].length == 3
46+
* 1 <= firsti <= lasti <= n
47+
* 1 <= seatsi <= 10ドル^4$
48+
49+
---
50+
51+
### 基本分析
52+
53+
本题只涉及「区间修改 + 单点查询」,属于「区间求和」问题中的入门难度。
54+
55+
对于各类「区间求和」问题,该用什么方式进行求解,之前在 [这里](https://leetcode-cn.com/problems/range-sum-query-mutable/solution/guan-yu-ge-lei-qu-jian-he-wen-ti-ru-he-x-41hv/) 提到过。
56+
57+
此处可以再总结一下(加粗字体为最佳方案):
58+
59+
* 数组不变,区间查询:**前缀和**、树状数组、线段树;
60+
* 数组单点修改,区间查询:**树状数组**、线段树;
61+
* 数组区间修改,单点查询:**差分**、线段树;
62+
* 数组区间修改,区间查询:**线段树**
63+
64+
> 注意:上述总结是对于一般性而言的(能直接解决的),对标的是模板问题。
65+
但存在经过一些经过"额外"操作,对问题进行转化,从而使用别的解决方案求解的情况。
66+
例如某些问题,我们可以先对原数组进行差分,然后使用树状数组,也能解决区间修改问题。
67+
或者使用多个树状数组来维护多个指标,从而实现类似线段树的持久化标记操作。
68+
但这些不属于一般性,所以就不添加到题解了。
69+
70+
---
71+
72+
### 差分
73+
74+
本题只涉及「区间修改 + 单点查询」,因此是一道「差分」的模板题。
75+
76+
「差分」可以看做是求「前缀和」的逆向过程。
77+
78+
对于一个「将区间 $[l, r]$ 整体增加一个值 $v$」操作,我们可以对差分数组 $c$ 的影响看成两部分:
79+
80+
* 对 $c[l] += v$:由于差分是前缀和的逆向过程,这个操作对于将来的查询而言,带来的影响是对于所有的下标大于等于 $l$ 的位置都增加了值 $v$;
81+
* 对 $c[r + 1] -= v$:由于我们期望只对 $[l, r]$ 产生影响,因此需要对下标大于 $r$ 的位置进行减值操作,从而抵消"影响"。
82+
83+
对于最后的构造答案,可看做是对每个下标做"单点查询"操作,只需要对差分数组求前缀和即可。
84+
85+
代码:
86+
```Java
87+
class Solution {
88+
public int[] corpFlightBookings(int[][] bs, int n) {
89+
int[] c = new int[n + 1];
90+
for (int[] bo : bs) {
91+
int l = bo[0] - 1, r = bo[1] - 1, v = bo[2];
92+
c[l] += v;
93+
c[r + 1] -= v;
94+
}
95+
int[] ans = new int[n];
96+
ans[0] = c[0];
97+
for (int i = 1; i < n; i++) {
98+
ans[i] = ans[i - 1] + c[i];
99+
}
100+
return ans;
101+
}
102+
}
103+
```
104+
* 时间复杂度:预处理差分数组的复杂度为 $O(n)$;构造答案复杂度为 $O(n)$。整体复杂度为 $O(n)$
105+
* 空间复杂度:$O(n)$
106+
107+
---
108+
109+
### 线段树
110+
111+
在「基本分析」中,我们发现几乎所有的「区间求和」问题都可以使用线段树解决。
112+
113+
那么是否无脑写线段树呢?答案并不是,恰好相反。
114+
115+
线段树代码很长,且常数很大,实际表现不算很好。只有不得不写「线段树」的时候,我们才考虑线段树。
116+
117+
回到本题,由于涉及「区间修改」操作,因此我们需要对线段树进行持久化标记(懒标记),从而确保操作仍为 $\log$ 级别的复杂度。
118+
119+
代码:
120+
```Java
121+
class Solution {
122+
class Node {
123+
int l, r, v, add;
124+
Node(int _l, int _r) {
125+
l = _l; r = _r;
126+
}
127+
}
128+
int N = 20009;
129+
Node[] tr = new Node[N * 4];
130+
void pushup(int u) {
131+
tr[u].v = tr[u << 1].v + tr[u << 1 | 1].v;
132+
}
133+
void pushdown(int u) {
134+
int add = tr[u].add;
135+
tr[u << 1].v += add;
136+
tr[u << 1].add += add;
137+
tr[u << 1 | 1].v += add;
138+
tr[u << 1 | 1].add += add;
139+
tr[u].add = 0;
140+
}
141+
void build(int u, int l, int r) {
142+
tr[u] = new Node(l, r);
143+
if (l != r) {
144+
int mid = l + r >> 1;
145+
build(u << 1, l, mid);
146+
build(u << 1 | 1, mid + 1, r);
147+
}
148+
}
149+
void update(int u, int l, int r, int v) {
150+
if (l <= tr[u].l && tr[u].r <= r) {
151+
tr[u].v += v;
152+
tr[u].add += v;
153+
} else {
154+
pushdown(u);
155+
int mid = tr[u].l + tr[u].r >> 1;
156+
if (l <= mid) update(u << 1, l, r, v);
157+
if (r > mid) update(u << 1 | 1, l, r, v);
158+
pushup(u);
159+
}
160+
}
161+
int query(int u, int l, int r) {
162+
if (l <= tr[u].l && tr[u].r <= r) {
163+
return tr[u].v;
164+
} else {
165+
pushdown(u);
166+
int mid = tr[u].l + tr[u].r >> 1;
167+
int ans = 0;
168+
if (l <= mid) ans += query(u << 1, l, r);
169+
if (r > mid) ans += query(u << 1 | 1, l, r);
170+
return ans;
171+
}
172+
}
173+
public int[] corpFlightBookings(int[][] bs, int n) {
174+
build(1, 1, n);
175+
for (int[] bo : bs) {
176+
update(1, bo[0], bo[1], bo[2]);
177+
}
178+
int[] ans = new int[n];
179+
for (int i = 0; i < n; i++) {
180+
ans[i] = query(1, i + 1, i + 1);
181+
}
182+
return ans;
183+
}
184+
}
185+
```
186+
* 时间复杂度:线段树建树复杂度为 $O(n),ドル其余操作复杂度为 $O(\log{n})$。对于本题,令 `bs` 长度为 $m,ドル整体复杂度为 $O(m\log{n} + n\log{n})$
187+
* 空间复杂度:$O(n)$
188+
189+
---
190+
191+
### 最后
192+
193+
这是我们「刷穿 LeetCode」系列文章的第 `No.1109` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
194+
195+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
196+
197+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
198+
199+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
200+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /