352. Data Stream as Disjoint Intervals

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?

方法1:

参考:https://blog.csdn.net/qq508618087/article/details/51553166

思路:

联想到128. Longest Consecutive Sequence中online的方法,用hash保持每个点所在interval的长度, 但是和这道题不太一样,没有办法用hash端点的办法keep track of all interval。这道题的第一种做法是每次进入一个新数字都要遍历一次已经存在的区间,不太高效。题目说考虑区间比较少而merge很多的情况,也就是说会产生很多最后一步的插入,由于是vector,会造成位移。

Complexity

Time complexity: O(kN)
Space complexity: O(N), 每次都用到了额外的tmp数组

易错点:

  1. Inverval (val, val)
  2. 融合条件是interval.end + 1 >= v.start && interval.start <= v.end+ 1
  3. 应该有更efficient的方法in place修改result。否则需要创建一个新的tmp,转移结果,最后再赋值给result,否则遍历result时push_back to result会overflow。
/**
 * Definition for an interval.
 * struct Interval {
 *     int start;
 *     int end;
 *     Interval() : start(0), end(0) {}
 *     Interval(int s, int e) : start(s), end(e) {}
 * };
 */
class SummaryRanges {
public:
    /** Initialize your data structure here. */
    SummaryRanges() {
        
    }
    
    void addNum(int val) {
        int cur = 0;
        Interval v = Interval(val, val);
        vector<Interval> tmp;
        
        for (auto interval: result){
            
            if (interval.end + 1 < v.start){
                tmp.push_back(interval);
                cur++;                
            }
            else if (v.end + 1 < interval.start){
                tmp.push_back(interval);
                
            }
            else {
                v.start = min(interval.start, v.start);
                v.end = max(interval.end, v.end);
            }
        }
        tmp.insert(tmp.begin() + cur, v);
        result = tmp;
    }
    
    vector<Interval> getIntervals() {
        return result;
    }
private: 
    vector<Interval> result;
};

/**
 * Your SummaryRanges object will be instantiated and called as such:
 * SummaryRanges* obj = new SummaryRanges();
 * obj->addNum(val);
 * vector<Interval> param_2 = obj->getIntervals();
 */

方法2:

主要利用了iterator,用vector::lower_bound 找到最小的大于Interval(val, val)的区间(这里的cmp自定义为起点序),将它的iterator定义为it。从这个区间开始,之后的所有区间如果满足( it -> start <= val + 1 ),那么一定和Interval(val, val)发生merge。除此以外,lower_bound 之前的interval(或一个单独的整数),虽然start < val,但是如果满足(it -> end <= val - 1) 仍然会发生merge,需要按需持续it–。那么有了iterator之后,每次发生融合,只需要用vector::erase(it)就可以原位删除区间,最后将融合的新区间vector::insert(it, Interval(start, end)),也就是再加入 it 退出的位置(下一个不融合的区间)之前就可以了。原位修改,利用iterator,提速很多。

Complexity

Time complexity: O(kN)
Space complexity: O(1)

易错点:

  1. 这里融合的条件是
    it -> start <= val + 1 && val <= it -> end + 1
    和merge intervals的条件不一样。因为相邻正整数在这里也需要merge。
  2. 不要漏掉前面另一个可能的interval:(更正)不止一个,要用while loop找出所有
  3. vector::insert(it, Interval()), 插入在该iterator之前
class SummaryRanges {
public:
    void addNum(int val) {
        auto cmp = [](Interval a, Interval b) { return a.start < b.start; };
        auto it = lower_bound(vec.begin(), vec.end(), Interval(val, val), cmp);
        int start = val, end = val;
        while (it != vec.begin() && (it-1)->end+1 >= val) it--;
        while(it != vec.end() && val+1 >= it->start && val-1 <= it->end)
        {
            start = min(start, it->start);
            end = max(end, it->end);
            it = vec.erase(it);
        }
        vec.insert(it,Interval(start, end));
    }
    
    vector<Interval> getIntervals() {
        return vec;
    }
private:
    vector<Interval> vec;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值