352.Data Stream as Disjoint Intervals
===
###### tags: `Hard`,`Binary Search`,`Design`,`Ordered Set`
[352. Data Stream as Disjoint Intervals](https://leetcode.com/problems/data-stream-as-disjoint-intervals/)
### 題目描述
Given a data stream input of non-negative integers `a1, a2, ..., an`, summarize the numbers seen so far as a list of disjoint intervals.
Implement the `SummaryRanges` class:
* `SummaryRanges()` Initializes the object with an empty stream.
* `void addNum(int value)` Adds the integer `value` to the stream.
* `int[][] getIntervals()` Returns a summary of the integers in the stream currently as a list of disjoint intervals [$start_i$, $end_i$]. The answer should be sorted by $start_i$.
### 範例
**Example 1:**
```
Input
["SummaryRanges", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals"]
[[], [1], [], [3], [], [7], [], [2], [], [6], []]
Output
[null, null, [[1, 1]], null, [[1, 1], [3, 3]], null, [[1, 1], [3, 3], [7, 7]], null, [[1, 3], [7, 7]], null, [[1, 3], [6, 7]]]
Explanation
SummaryRanges summaryRanges = new SummaryRanges();
summaryRanges.addNum(1); // arr = [1]
summaryRanges.getIntervals(); // return [[1, 1]]
summaryRanges.addNum(3); // arr = [1, 3]
summaryRanges.getIntervals(); // return [[1, 1], [3, 3]]
summaryRanges.addNum(7); // arr = [1, 3, 7]
summaryRanges.getIntervals(); // return [[1, 1], [3, 3], [7, 7]]
summaryRanges.addNum(2); // arr = [1, 2, 3, 7]
summaryRanges.getIntervals(); // return [[1, 3], [7, 7]]
summaryRanges.addNum(6); // arr = [1, 2, 3, 6, 7]
summaryRanges.getIntervals(); // return [[1, 3], [6, 7]]
```
**Constraints**:
* 0 <= `value` <= 10^4^
* At most 3 * 10^4^ calls will be made to `addNum` and `getIntervals`.
**Follow up**: What if there are lots of merges and the number of disjoint intervals is small compared to the size of the data stream?
### 解答
#### C++
##### 方法1
1. 先將每次拿到的數字放入一個「有序的set」
2. 因為有序,所以一個一個拿出來時檢查是否為前一個+1就好
3. 若超過前一個+1則建立新的區間
```cpp=
class SummaryRanges {
public:
set<int> data;
SummaryRanges() {
}
void addNum(int value) {
data.insert(value);
}
vector<vector<int>> getIntervals() {
vector<vector<int>> ans;
if (data.empty()) return ans;
int start = *data.begin();
int end = start;
for (auto value : data) {
if (value > end + 1) {
ans.push_back({start, end});
start = end = value;
} else {
end = value;
}
}
ans.push_back({start, end});
return ans;
}
};
```
> [name=Yen-Chi Chen][time=Mon, Jan 30, 2023]
##### 方法2
1. 利用「有序的map」來記錄。把key當作區間的開端,value當作區間的結尾
2. 接著用binary search (upper_bound)來找到大於value的key中最小的一個。再跟前後兩個區間進行比較,來決定新的區間如何建立,以及是否移除舊的區間。
```cpp=
class SummaryRanges {
public:
map<int, int> intervals;
SummaryRanges() {
}
void addNum(int value) {
int start = value, end = value;
auto upper = intervals.upper_bound(value);
if (upper != intervals.begin()) {
auto target = prev(upper);
if (target->second >= value) return;
if (target->second + 1 == value) {
start = target->first;
}
}
if (upper != intervals.end() && upper->first == value + 1) {
end = upper->second;
intervals.erase(upper);
}
intervals[start] = end;
}
vector<vector<int>> getIntervals() {
vector<vector<int>> ans;
for (const auto &interval : intervals) {
ans.push_back({interval.first, interval.second});
}
return ans;
}
};
```
### Reference
[回到題目列表](https://hackmd.io/@Marsgoat/leetcode_every_day)