返回

我的日程安排表 III:线段树(动态开点)运用题

后端

我的日程安排表 III:线段树(动态开点)运用题


前言

大家好,我是 掘金日新计划 的参与者。在持续创作的第28天,我选择分享一道 LeetCode 题解——732. 我的日程安排表 III。这道题涉及动态规划和线段树的知识,具有一定挑战性。希望我的分享能给大家带来启发。

题目

给你一个数组 events,其中 events[i] = [start_i, end_i] 表示第 i 个会议的起始时间 start_i 和结束时间 end_i (均为整数)。

你需要安排一场会议,让参加这场会议的人员数目最大化。如果两场会议时间部分重叠,那么它们不能同时进行。

返回你可以安排的最大的会议数目。

示例

输入:events = [[1, 2], [2, 3], [3, 4], [1, 5]]
输出:2
输入:events = [[1, 10], [2, 7], [3, 19], [8, 12], [10, 20], [11, 16], [17, 25]]
输出:4

思路分析

这道题可以看作是一个动态规划问题。我们定义 dp[i] 为在考虑前 i 个会议时,能够安排的最大会议数目。为了计算 dp[i],我们需要考虑以下两种情况:

  • 不安排第 i 个会议:在这种情况下,dp[i] 等于 dp[i-1]。
  • 安排第 i 个会议:在这种情况下,我们需要找到一个最大的 j,使得会议 j 和会议 i 没有重叠。然后,dp[i] 等于 max(dp[i-1], dp[j] + 1)。

为了找到最大的 j,我们可以使用线段树来维护会议的区间。这样,我们可以在 O(log n) 的时间内找到最大的 j。

代码实现

import java.util.Arrays;

public class MyCalendarThree {

    private class SegmentTreeNode {
        int start;
        int end;
        int count;
        SegmentTreeNode left;
        SegmentTreeNode right;

        public SegmentTreeNode(int start, int end) {
            this.start = start;
            this.end = end;
        }
    }

    private SegmentTreeNode root;

    public MyCalendarThree() {

    }

    public int book(int start, int end) {
        update(root, start, end - 1);
        return query(root);
    }

    private void update(SegmentTreeNode node, int start, int end) {
        if (node == null) {
            node = new SegmentTreeNode(start, end);
        }
        if (start <= node.start && end >= node.end) {
            node.count++;
        } else {
            int mid = (node.start + node.end) / 2;
            if (start <= mid) {
                update(node.left, start, end);
            }
            if (end > mid) {
                update(node.right, start, end);
            }
        }
    }

    private int query(SegmentTreeNode node) {
        if (node == null) {
            return 0;
        }
        return Math.max(node.count, Math.max(query(node.left), query(node.right)));
    }

    public static void main(String[] args) {
        MyCalendarThree myCalendarThree = new MyCalendarThree();
        int[][] events = {{1, 2}, {2, 3}, {3, 4}, {1, 5}};
        for (int[] event : events) {
            int maxCount = myCalendarThree.book(event[0], event[1]);
            System.out.println("Max count after booking event: " + Arrays.toString(event) + " is " + maxCount);
        }
    }
}

总结

这道题涉及动态规划和线段树的知识,具有一定挑战性。通过分析题意,我们可以将其转化为一个动态规划问题。使用线段树来维护会议的区间,可以帮助我们在 O(log n) 的时间内找到最大的 j,从而计算出 dp[i]。

希望我的分享能给大家带来启发。如果大家有任何问题,欢迎在评论区留言。

参考资料


专项元素