2019-06-01

LeetCode 352. Data Stream as Disjoint Intervals

352. Data Stream as Disjoint Intervals.jpg

Description

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.

描述

给定一个非负整数的数据流输入 a1,a2,…,an,…,将到目前为止看到的数字总结为不相交的区间列表。

例如,假设数据流中的整数为 1,3,7,2,6,…,每次的总结为:

[1, 1]
[1, 1], [3, 3]
[1, 1], [3, 3], [7, 7]
[1, 3], [7, 7]
[1, 3], [6, 7]

进阶:
如果有很多合并,并且与数据流的大小相比,不相交区间的数量很小,该怎么办?

思路

  • 把一个数插入到区间中,如果这个数与某个区间的头部(或尾部)相差 1,那么这个区间就应当被扩大。
  • 如对于已经存在的区间如[[1,3],[6,9]],向里面插入 4,由于 4 和 第一个区间的末尾 3 相差 1,于是第一个区间被扩大,结果为[[1,4],[6,9]]。
  • 对于区间 [[1,4],[6,9]],向里面插入 5 ,由于 5 和第一个区间末尾相差1,与 第二个区间的头部相差1,于是 5 把这两个区间连在了一起,结果为 [[1,9]]。
  • 用 added 存储已经用过形成区间的数字,num_bisect 存储下一次需要用于形成区间的数字,invs 存储所有的区间。
  • 我们要做的就是依次将 num_bisect 中的数字 num 添加到区间中,则有如下情况:
  1. 如果 num 已经出现在了 added 中,说名此数已经形成了区间,继续下一个循环;
  2. 如果 num 比区间 i 的右边界大 1,如下图 1,那么区间 i 需要扩大右边界,如果此时刚好 num 比 区间 i+1 的左边界小 1,那么需要将 区间 i 和 i+1 合并,如图 2;


    1.png
4.png
  1. 如果 num 比区间 i 的左边界小 1,如图 3,那区间 i 需要扩大左边界(这里不用考虑合并两个去区间的问题,因为在情况 2 中会会被合并)


    2.png
  2. 如果 num 没有与任意一个区间短点相差 1,则创建新的区间。


    3.png
# -*- coding: utf-8 -*-
# @Author:             何睿
# @Create Date:        2019-06-01 16:53:14
# @Last Modified by:   何睿
# @Last Modified time: 2019-06-01 18:25:18

import bisect
from typing import List, Dict, Set


class SummaryRanges(object):
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.added = set()  # type:Set([int])
        self.num_bisect = list()  # type:List[int]
        # 第一个区间初始化为 -2,或者比 -2 更小的数
        self.invs = [[-2, -2]]  # type:List[List[int]]

    def addNum(self, val: int) -> None:

        # 如果 val 已经被添加过,那么不用再次添加
        if val in self.added: return
        self.added.add(val)
        # 用 bisect 将数字插入到数组中,为下一次生成区间做准备
        # 在这里使用 insort_left 或 insort_right 效果一样
        bisect.insort_left(self.num_bisect, val)

    def getIntervals(self) -> List[List[int]]:

        # 外层循环,为每一个 num 找到其应该落在的区间
        for num in self.num_bisect:
            # 内层循环,遍历每一个区间
            for i in range(len(self.invs)):
                # 如果 num 在区间 invs[i] 的内部,则什么都不做
                if self.invs[i][0] < num < self.invs[i][1]:
                    break

                # 如果 num 在区间的 self.invs[i] 的右边一个
                # 则扩充 self.invs[i] 区间
                elif num == self.invs[i][1] + 1:
                    self.invs[i][1] += 1

                    # 如果 self.invs[i] 后面还有区间
                    # 并且 num 和 self.invs[i+1]的左边界相差 1
                    # 将区间 self.invs[i] 与 self.invs[i+1]合并,删除 self.invs[i+1]
                    if i + 1 < len(self.invs):
                        if self.invs[i + 1][0] == num + 1:
                            self.invs[i][1] = self.invs[i + 1][1]
                            del self.invs[i + 1]
                    break
                
                # 如果 num 在区间的 self.invs[i] 的左边一个
                # 扩充左区间
                elif num + 1 == self.invs[i][0]:
                    self.invs[i][0] = num
                    break
                else:
                    # 如果 num 比前一个区间的尾部值大并到了最后一个位置
                    if i + 1 == len(self.invs) and num > self.invs[i][1] + 1:
                        self.invs.append([num, num])
                        break
                     # 如果 num 比前一个区间的尾部值大比后一个区间前部值小
                    elif self.invs[i][1] + 1 < num < self.invs[i + 1][0] - 1:
                        self.invs.insert(i + 1, [num, num])

        self.num_bisect = list()
        return self.invs[1:]

源代码文件在 这里
©本文首发于 何睿的博客 ,欢迎转载,转载需保留 文章来源 ,作者信息和本声明.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容