【LeetCode】729. 我的日程安排表 I

image.png

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

测试岗位也越来卷了,除了基本的功能测试外,还要有编程基础、脚本经验才脱颖而出。

怎么才能提高我们的编程能力呢,刷LeetCode是最佳的途径之一,话不多数,刷题走起~

一、题目描述:

  • 题目内容

    image.png

  • 题目示例

    image.png

  • 题目解析

    • 0 <= start < end <= 109
    • 每个测试用例,调用 book 方法的次数最多不超过 1000 次。

二、思路分析:

我们拿到本题,读取题目要构建一个日程安排表,对于每一次预定时间范围[start,end]进行预定操作,当最新的时间断与已经预定的时间段重合时,则不能进行预定。我们来看一下日常安排表对象构成情况:

  • Mycalendar类初始化日历对象
  • 时间段[start,end]是半开区间的,start <= t < end
  • book方法对时间段新的时间段[start,end]进行检查

对本题的内容进行了解后,解答本题我们可以直接使用模拟遍历方法解答即可,思路如下:

  • MyCalendar对象初始化时,创建一个booklist列表存储已预定的时间段
  • book方法中,需要判断[start,end]在booklist列表已预定的时间段是否有重合的
  • 通过区间我们可以快速找到重合时间段的判断条件即 start < e and end > s
  • 当时间段重合时,则直接返回False,反之则加入到booklist中并返回True image.png 我们按照上述思路,可以快速使用Python代码来实现,代码如下:
    class MyCalendar(object):
    
        def __init__(self):
            self.booklist = []
    
        def book(self, start, end):
            """
            :type start: int
            :type end: int
            :rtype: bool
            """
            for s,e in self.booklist:
                if s < end and e > start:
                    return False
            self.booklist.append([start,end])
            return True
    复制代码

对于一个列表中所有元素要求出指定位置之前的元素和,我们可以使用前缀和的思路,提前遍历列表把元素进行加法计算,在后续使用过程中,我们就可以直接取用,无需再进行繁琐的遍历列表了。

本题是涉及到区间判断的,我们会涉及到历史区间的遍历和更改,如果再使用前缀和,就能适用了。因此,涉及到新概念,线段树方法来实现。

  • 线段树中节点,主要包含三个字段第一个是左右孩子和懒惰标记
  • 线段树中主要的方法:build构建线段树、update更新线段树、query查询线段树
  • 线段树中数据查询和更新的时间复杂度为O(log2n)
    class MyCalendar(object):
    
        def __init__(self):
    
            self.tree = set()
            self.lazy = set()
    
        def query(self,start,end,l,r,idx):
            if r < start or end < l:
                return False
            if idx in self.lazy:  
                return True
            if start <= l and r <= end:
                return idx in self.tree
            mid = (l + r) // 2
            return self.query(start, end, l, mid, 2 * idx) or \
                   self.query(start, end, mid + 1, r, 2 * idx + 1)
    
        def update(self,start,end,l,r,idx):
            if r < start or end < l:
                return
            if start <= l and r <= end:
                self.tree.add(idx)
                self.lazy.add(idx)
            else:
                mid = (l + r) // 2
                self.update(start, end, l, mid, 2 * idx)
                self.update(start, end, mid + 1, r, 2 * idx + 1)
                self.tree.add(idx)
                if 2 * idx in self.lazy and 2 * idx + 1 in self.lazy:
                    self.lazy.add(idx)
    
        def book(self, start, end):
            """
            :type start: int
            :type end: int
            :rtype: bool
            """
    
            if self.query(start, end - 1, 0, 10 ** 9, 1):
                return False
            self.update(start, end - 1, 0, 10 ** 9, 1)
            return True
    
    复制代码

三、总结:

本题考察我们对于区间数据更新与判断,对比直接遍历模拟,线段树对于区间内数据更新和查询是更优的解法,AC提交记录如下:

image.png

  • 时间复杂度:O(nlogC),其中 n为日程安排的数量。logC为线段树中查询最多的节点数
  • 空间复杂度:O(nlogC),其中 n 为日程安排数量。logC为线段树中最多新增logC节点数

以上是本期内容,欢迎大佬们点赞评论,下期见~~~

猜你喜欢

转载自juejin.im/post/7128003629692223519