[LeetCode] 352. 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.

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

 

類似題目:

Insert Interval

Range Module

Find Right Interval 

Summary Ranges

 

參考資料:

https://leetcode.com/problems/data-stream-as-disjoint-intervals/

https://leetcode.com/problems/data-stream-as-disjoint-intervals/discuss/82557/Very-concise-c%2B%2B-solution.

https://leetcode.com/problems/data-stream-as-disjoint-intervals/discuss/82616/C%2B%2B-solution-using-map.-O(logN)-per-adding.

https://leetcode.com/problems/data-stream-as-disjoint-intervals/discuss/82553/Java-solution-using-TreeMap-real-O(logN)-per-adding.

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM