Given a data stream input of non-negative integers a1, a2, ..., an, ..., summarize the numbers seen so far as a list of disjoint intervals.
For example, suppose the integers from the data stream are 1, 3, 7, 2, 6, ..., then the summary will be:
[1, 1] [1, 1], [3, 3] [1, 1], [3, 3], [7, 7] [1, 3], [7, 7] [1, 3], [6, 7]
Follow up:
What if there are lots of merges and the number of disjoint intervals are small compared to the data stream's size?
NOTE: input types have been changed on April 15, 2019. Please reset to default code definition to get new method signature.
Credits:
Special thanks to @yunhong for adding this problem and creating most of the test cases.
這道題說有個數據流每次提供一個數字,然后讓我們組成一系列分離的區間,這道題跟之前那道 Insert Interval 很像,思路也很像,每進來一個新的數字 val,都生成一個新的區間 [val, val],並且新建一個空的區間數組 res,用一個變量 cur 來保存要在現有的區間數組中加入新區間的位置。此時遍歷現有的區間數組 intervals,對於每一個遍歷到的當前區間 interval,假如要加入的區間的結尾位置加1比當前區間的起始位置小,說明二者不相連,將當前區間加入 res。否則當要加入區間的起始位置大於當前位置的結束位置加1,說明二者也沒有交集,可以將當前區間加入 res,不過此時 cur 要自增1,因為要加入區間的位置在當前區間的后面。再否則的話,二者就會有交集,需要合並,此時用二者起始位置中較小的更新要加入區間的起始位置,同理,用二者結束位置中較大的去更新要加入區間的結束位置。最終將要加入區間放在 res 中的 cur 位置,然后將 res 賦值給 intervals 即可,參見代碼如下:
解法一:
class SummaryRanges { public: SummaryRanges() {} void addNum(int val) { vector<int> newInterval{val, val}; vector<vector<int>> res; int cur = 0; for (auto interval : intervals) { if (newInterval[1] + 1 < interval[0]) { res.push_back(interval); } else if (newInterval[0] > interval[1] + 1) { res.push_back(interval); ++cur; } else { newInterval[0] = min(newInterval[0], interval[0]); newInterval[1] = max(newInterval[1], interval[1]); } } res.insert(res.begin() + cur, newInterval); intervals = res; } vector<vector<int>> getIntervals() { return intervals; } private: vector<vector<int>> intervals; };
感謝熱心網友 greentrail 的提醒,我們可以對上面的解法進行優化。由於上面的方法每次添加區間的時候,都要把 res 賦值給 intervals,整個區間數組都要進行拷貝,十分的不高效。這里換一種方式,用一個變量 overlap 來記錄所有跟要加入區間有重疊的區間的個數,用變量i表示新區間要加入的位置,這樣只要最后 overlap 大於0了,現在 intervals 中將這些重合的區間刪掉,然后再將新區間插入,這樣就不用進行整體拷貝了,提高了效率,參見代碼如下:
解法二:
class SummaryRanges { public: SummaryRanges() {} void addNum(int val) { vector<int> newInterval{val, val}; int i = 0, overlap = 0, n = intervals.size(); for (; i < n; ++i) { if (newInterval[1] + 1 < intervals[i][0]) break; if (newInterval[0] <= intervals[i][1] + 1) { newInterval[0] = min(newInterval[0], intervals[i][0]); newInterval[1] = max(newInterval[1], intervals[i][1]); ++overlap; } } if (overlap > 0) { intervals.erase(intervals.begin() + i - overlap, intervals.begin() + i); } intervals.insert(intervals.begin() + i - overlap, newInterval); } vector<vector<int>> getIntervals() { return intervals; } private: vector<vector<int>> intervals; };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/352
類似題目:
參考資料:
https://leetcode.com/problems/data-stream-as-disjoint-intervals/