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、每进来一个新的数字val,我们都生成一个新的区间[val, val],然后将其插入到当前的区间里,注意分情况讨论,无重叠,相邻,和有重叠分开讨论处理:

class SummaryRanges {
public:
     struct Interval {
         int start;
         int end;
         Interval() : start(0), end(0) {}
         Interval(int s, int e) : start(s), end(e) {}
     };

    SummaryRanges() {}

    void addNum(int val) { //每插入一个元素就要遍历一遍所有的区间,分重叠,相邻,有重叠情况分别处理
        Interval cur(val, val);
        vector<Interval> res;
        int pos = 0;
        for (auto a : v) {
            if (cur.end + 1 < a.start) {//无重叠且在cur后,直接插入
                res.push_back(a);
            } else if (cur.start > a.end + 1) {//无重叠且在cur前,直接插入,并将pos+1,pos为cur最后将插入的位置
                res.push_back(a);
                ++pos;
            } else if (cur.start - 1 == a.end) {//相邻且在cur前,则和cur合并,将cur.start置为a.start
                cur.start = a.start;
            } else if (cur.end + 1 == a.start) {//相邻且在cur后,则和cur合并,将cur.end置为a.end
                cur.end = a.end;
            } else {//重叠也将两者合并,start和end分别取max,min
                cur.start = min(cur.start, a.start);
                cur.end = max(cur.end, a.end);
            }
        }
        res.insert(res.begin() + pos, cur);//插入cur
        v = res;
    }

    vector<Interval> getIntervals() {
        return v;    
    }

private:
    vector<Interval> v;
};

2、二分搜索树
在每个结点中设置一个变量range来保存区间,当新数据val到来时,中序遍历整个二叉树,如果val在root的range中则无需修改或添加结点,直接返回。左相邻则修改start然后找到左子树最靠右的结点观察是否需要合并。右相邻则修改end然后找到右子树最靠左的结点观察是否需要合并。不相邻则分大小分别向左,向右遍历子树。

//存在不平衡的问题
struct MMTreeNode
 {
     Interval range;
     MMTreeNode *left;
     MMTreeNode *right;
     MMTreeNode(int s, int e):range(s, e), left(NULL), right(NULL){}
 };

class SummaryRanges {
private:
    MMTreeNode *rt;

public:
    SummaryRanges() {
        rt = NULL;
    }

    void addNum(int val) {
        addNumHelper(val, rt);
    }

    void addNumHelper(int val, MMTreeNode *&root)
    {
        if(root == NULL)
        { //处理第一个结点
            root = new MMTreeNode(val, val);
            return;
        }
        //如果val在root的区间之内,直接返回
        if(root->range.start <= val && root->range.end >= val) return;
        if(root->range.start == val + 1)
        {
            root->range.start = val;
            //find the rightest node on the left subtree
            if(root->left)
            {
                MMTreeNode *node = root->left;
                if(node->right == NULL)
                {
                    //右子树不存在,即左边第一个range的end==val-1,合并,删除,返回
                    if(node->range.end == val - 1)
                    {
                        root->range.start = node->range.start;
                        root->left = node->left;
                        delete node;
                    }
                    return;
                }
                //右子树存在,则找到最右的结点,(即root左子树中最大range)
                MMTreeNode *parent;
                while(node->right)
                {
                    parent = node;
                    node = node->right;
                }
                if(node->range.end == val - 1) //若最右的range的end==val-1,合并,删除,返回
                {
                    parent->right = node->left;
                    root->range.start = node->range.start;
                    delete node;
                }
            }
            return;
        }else if(root->range.end == val - 1)
        {
            root->range.end = val;
            //找到右子树中最左的结点
            if(root->right)
            {
                MMTreeNode *node = root->right;
                if(node->left == NULL)
                {
                    //如果左子树不存在,则找到的子树的根节点即为最左的结点
                    if(node->range.start == val + 1)
                    {
                        root->range.end = node->range.end;
                        root->right = node->right;
                        delete node;
                    }
                    return;
                }
                //如果左子树存在,则找到左子树中最左的结点
                MMTreeNode *parent = root;
                while(node->left)
                {
                    parent = node;
                    node = node->left;
                }
                if(node->range.start == val + 1)
                {
                    parent->left = node->right;
                    root->range.end = node->range.end;
                    delete node;
                }
            }
            return;
        }else if(root->range.start > val) //与start,end都不相邻的情况,小于start
        {
            addNumHelper(val, root->left); 
        }else                             //与start,end都不相邻的情况,大于end
        {
            addNumHelper(val, root->right);
        }
    }

    vector<Interval> getIntervals() {
        vector<Interval> result;
        getIntervalsHelper(rt, result);
        return result;
    }

    //中序遍历所有结点,将每个结点的range保存到result中
    void getIntervalsHelper(MMTreeNode *root, vector<Interval> &result)
    {
        if(root == NULL) return;
        getIntervalsHelper(root->left, result);
        result.push_back(root->range);
        getIntervalsHelper(root->right, result);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值