Skip to content

Commit c9514f5

Browse files
author
lucifer
committed
feat: - [Number Stream to Intervals]
1 parent 95ea925 commit c9514f5

File tree

3 files changed

+165
-0
lines changed

3 files changed

+165
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ leetcode 题解,记录自己的 leetcode 解题之路。
400400
以下是我列举的经典题目(带 91 字样的表示出自 **91 天学算法**活动):
401401

402402
- [LCP 20. 快速公交](./problems/lcp20.meChtZ.md) 🆕
403+
- [Number Stream to Intervals](./problems/Number-Stream-to-Intervals.md) 🆕
403404

404405
- [0004. 寻找两个正序数组的中位数](./problems/4.median-of-two-sorted-arrays.md)
405406
- [0023. 合并 K 个升序链表](./problems/23.merge-k-sorted-lists.md)

SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@
236236
- [第六章 - 高频考题(困难)](collections/hard.md)
237237

238238
- [LCP 20. 快速公交](./problems/lcp20.meChtZ.md) 🆕
239+
- [Number Stream to Intervals](./problems/Number-Stream-to-Intervals.md) 🆕
239240
- [0004. 寻找两个正序数组的中位数](./problems/4.median-of-two-sorted-arrays.md)
240241
- [0023. 合并 K 个升序链表](./problems/23.merge-k-sorted-lists.md)
241242
- [0025. K 个一组翻转链表](./problems/25.reverse-nodes-in-k-groups.md)
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
## 题目地址(820.Number Stream to Intervals)
2+
3+
https://binarysearch.com/problems/Number-Stream-to-Intervals
4+
5+
## 题目描述
6+
7+
```
8+
Implement a data structure with the following methods:
9+
10+
StreamSummary() constructs a new instance.
11+
add(int val) adds the number val to the instance.
12+
int[][] get() returns a sorted list of disjoint intervals summarizing the numbers we've seen so far.
13+
Constraints
14+
15+
n ≤ 10,000 where n is the number of calls to add
16+
m ≤ 10,000 where n is the number of calls to get
17+
Example 1
18+
Input
19+
methods = ["constructor", "add", "add", "add", "add", "get"]
20+
arguments = [[], [1], [3], [2], [9], []]`
21+
Output
22+
[None, None, None, None, None, [
23+
[1, 3],
24+
[9, 9]
25+
]]
26+
Explanation
27+
s = StreamSummary()
28+
s.add(1)
29+
s.add(3)
30+
s.add(2)
31+
s.add(9)
32+
s.get() == [[1, 3], [9, 9]]
33+
Example 2
34+
Input
35+
methods = ["constructor", "add", "add", "add", "add", "get"]
36+
arguments = [[], [1], [2], [4], [3], []]`
37+
Output
38+
[None, None, None, None, None, [
39+
[1, 4]
40+
]]
41+
Explanation
42+
s = StreamSummary()
43+
s.add(1)
44+
s.add(2)
45+
s.add(4)
46+
s.add(3)
47+
s.get() == [[1, 4]]
48+
```
49+
50+
## 前置知识
51+
52+
- 哈希表
53+
- 有序哈希表
54+
- 二分法
55+
56+
## 思路
57+
58+
这道题是给我们一个数据流。由于是流,因此不是一次性给我们的。题目的意思是每次 add 都会增加一个 [val, val] 的左右闭合的区间。如果 add 的区间**与左边或者右边能够合并**,我们需要将其合并,get 需要返回合并之后的区间总和。
59+
60+
以题目中的:
61+
62+
```py
63+
s.add(1)
64+
s.add(3)
65+
s.add(2)
66+
s.add(9)
67+
68+
```
69+
70+
为例。
71+
72+
我们分步看一下合并后的区间情况。
73+
74+
```py
75+
s.add(1) # [ [1,1] ]
76+
s.add(3) # [ [1,1], [3,3] ]
77+
s.add(2) # [ [1,1], [2,2], [3,3] ] 可合并为 [ [1,3] ]
78+
s.add(9) # [ [1,3], [9,9] ]
79+
```
80+
81+
因此这个时候调用 get 会返回 `[ [1,3], [9,9] ]`
82+
83+
题目意思就是这样,接下来我们只需要模拟即可。由于每次 add 都需要判断其是否会和前面的区间或者后面的区间进行合并,因此我们可以使用两个哈希表存储。
84+
85+
- 哈希表 start 其中 start[x] 表示以 x 为区间左端点的区间的右端点,也就是说其表示的是区间 [ x, start[x] ]
86+
- 哈希表 end 其中 end[x] 表示以 x 为区间右端点的区间的左端点,也就是说其表示的是区间 [ end[x], x ]
87+
88+
这样 add 的时候就有四种情况:
89+
90+
- 仅和左边区间结合,也就是说 val - 1 在 end 中。此时 [a,val-1],[val+1,b] 可以和 [val,val] 合并为 [a,b]
91+
- 仅和右边区间结合,也就是说 val + 1 在 start 中.此时 [val+1,b] 可以和 [val,val] 合并为 [val,b]
92+
- 和左右边区间都结合,也就是说 val - 1 在 end 中 且 val + 1 在 start 中.此时 [a,val-1] 可以和 [val,val] 合并为 [a,val]
93+
- 不和左右区间结合
94+
95+
根据上面的四种情况更新 start 和 end 即可。需要注意的是更新了区间(区间合并)之后,需要将原有的区间从哈希表移除,以免影响最终结果。
96+
97+
由于题目说明了 get 返回值需要是升序排序的,而普通的哈希表是乱序的。因此我们需要:
98+
99+
- get 部分对哈希表进行排序之后再返回
100+
101+
这种做法 add 时间复杂度为 $O(1)$,get 时间复杂度为 $mlogm$,m 为合并后的区间个数。
102+
103+
- 使用 SortedDict
104+
105+
由于 SortedDict 内部使用的是平衡树,因此 add 时间复杂度为 $O(logn)$, get 时间复杂度为 $O(m)$,m 为合并后的区间个数。
106+
107+
这两种方法都可以,大家可以根据 add 和 get 的调用频率以及 m 和 n 的大小关系决定使用哪一种。
108+
109+
## 代码
110+
111+
代码支持:Python3
112+
113+
Python3 Code:
114+
115+
```py
116+
from sortedcontainers import SortedDict
117+
118+
119+
class StreamSummary:
120+
def __init__(self):
121+
self.start = SortedDict()
122+
self.end = SortedDict()
123+
124+
def add(self, val):
125+
if val - 1 in self.end and val + 1 in self.start:
126+
# [a, val-1] + [val,val] + [val+1, b] -> [a, b]
127+
self.end[self.start[val + 1]] = self.end[val - 1]
128+
self.start[self.end[val - 1]] = self.start[val + 1]
129+
del self.start[val + 1]
130+
del self.end[val - 1]
131+
elif val - 1 in self.end:
132+
# [a, val -1] + [val, val] -> [a, val]
133+
self.end[val] = self.end[val - 1]
134+
self.start[self.end[val]] = val
135+
del self.end[val - 1]
136+
elif val + 1 in self.start:
137+
# [val,val] + [val+1, b] -> [val, b]
138+
self.start[val] = self.start[val + 1]
139+
self.end[self.start[val]] = val
140+
del self.start[val + 1]
141+
else:
142+
self.start[val] = val
143+
self.end[val] = val
144+
145+
def get(self):
146+
# iterate start or end get same correct answer
147+
ans = []
148+
for s, e in self.start.items():
149+
ans.append([s, e])
150+
return ans
151+
152+
```
153+
154+
**复杂度分析**
155+
156+
令 n 为数据流长度,m 为合并后的区间个数。
157+
158+
- 时间复杂度:add 时间复杂度为 $O(logn)$, get 时间复杂度为 $O(m)$
159+
- 空间复杂度:$O(m)$
160+
161+
力扣的小伙伴可以[关注我](https://leetcode-cn.com/u/fe-lucifer/),这样就会第一时间收到我的动态啦~
162+
163+
以上就是本文的全部内容了。大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 39K star 啦。大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。

0 commit comments

Comments
 (0)