返回

用线段树来管理日程安排:更高效且更具灵活性

后端

线段树是一种强大的数据结构,它通过将区间划分为更小的子区间,并对每个子区间存储信息的方式来实现高效的查询和修改操作。这种分治的思想使线段树能够在 O(log n) 的时间复杂度内完成这些操作。

现在,我们开始构建一个基于线段树的 MyCalendar 类。首先,我们定义一个线段树的结点结构:

class Node:
    def __init__(self, start, end):
        self.start = start
        self.end = end
        self.left = None
        self.right = None
        self.booked = False

在这个结构中,每个结点包含了区间的开始和结束时间,以及指向左右子结点的指针。此外,我们还添加了一个 booked 变量,用于标记该区间是否被预订。

接下来,我们定义一些操作来对线段树进行操作:

  • insert(start, end):将一个新的区间插入线段树中。
  • query(start, end):查询指定区间内是否有预订。
  • merge(node1, node2):将两个线段树结点合并成一个结点。

在实现这些操作之前,我们需要先初始化线段树。我们可以使用以下代码来完成:

def __init__(self):
    self.root = None

接下来,我们实现 insert 操作:

def insert(self, start, end):
    self.root = self._insert(self.root, start, end)

def _insert(self, node, start, end):
    if node is None:
        return Node(start, end)

    if start <= node.start and end >= node.end:
        node.booked = True
        return node

    if start > node.end or end < node.start:
        return node

    node.left = self._insert(node.left, start, end)
    node.right = self._insert(node.right, start, end)

    return node

insert 操作中,我们首先检查是否存在一个子区间完全包含要插入的区间。如果存在,则将该子区间的 booked 变量设为 True,并返回该子区间。如果不存在,则检查要插入的区间是否与子区间相交。如果相交,则将要插入的区间插入到左右子区间中,并更新左右子区间的 booked 变量。

接下来,我们实现 query 操作:

def query(self, start, end):
    return self._query(self.root, start, end)

def _query(self, node, start, end):
    if node is None:
        return False

    if start <= node.start and end >= node.end:
        return node.booked

    if start > node.end or end < node.start:
        return False

    return self._query(node.left, start, end) or self._query(node.right, start, end)

query 操作中,我们首先检查是否存在一个子区间完全包含要查询的区间。如果存在,则返回该子区间的 booked 变量。如果不存在,则检查要查询的区间是否与子区间相交。如果相交,则递归地查询左右子区间,并返回查询结果的逻辑或。

最后,我们实现 merge 操作:

def merge(self, node1, node2):
    if node1 is None:
        return node2
    if node2 is None:
        return node1

    node1.start = min(node1.start, node2.start)
    node1.end = max(node1.end, node2.end)
    node1.booked = node1.booked or node2.booked

    node1.left = self.merge(node1.left, node2.left)
    node1.right = self.merge(node1.right, node2.right)

    return node1

merge 操作中,我们将两个线段树结点合并成一个结点。首先,我们将两个结点的开始时间和结束时间取最小值和最大值,并将 booked 变量设置为两个结点的 booked 变量的逻辑或。然后,我们将两个结点的左右子结点分别合并,并返回合并后的结点。

这就是基于线段树的 MyCalendar 类的实现。我们可以使用它来高效地管理日程安排。