【leetcode】最多可以参加的会议数目 (小顶堆+贪心)

给你一个数组 events,其中 events[i] = [startDayi, endDayi] ,表示会议 i 开始于 startDayi ,结束于 endDayi 。

你可以在满足 startDayi <= d <= endDayi 中的任意一天 d 参加会议 i 。注意,一天只能参加一个会议。

请你返回你可以参加的 最大 会议数目。

示例 1:

输入:events = [[1,2],[2,3],[3,4]]
输出:3
解释:你可以参加所有的三个会议。
安排会议的一种方案如上图。
第 1 天参加第一个会议。
第 2 天参加第二个会议。
第 3 天参加第三个会议。
示例 2:

输入:events= [[1,2],[2,3],[3,4],[1,2]]
输出:4
示例 3:

输入:events = [[1,4],[4,4],[2,2],[3,4],[1,1]]
输出:4
示例 4:

输入:events = [[1,100000]]
输出:1
示例 5:

输入:events = [[1,1],[1,2],[1,3],[1,4],[1,5],[1,6],[1,7]]
输出:7

提示:

1 <= events.length <= 10^5
events[i].length == 2
1 <= events[i][0] <= events[i][1] <= 10^5

链接:https://leetcode-cn.com/problems/maximum-number-of-events-that-can-be-attended

思路分析:

这是一道知道贪心但是不知道怎么贪心的题…
首先,这道题满足贪心的性质是:每一天选择参加距当前结束时间最快的会议可推出全局最优解。
关键就是,如何找到当天结束时间最快的会议。

一开始本能的想法是定义一个数组 a[i] 表示以 i 为起始时间,结束时间最短的会议,然后按起始时间从小到大排序优化一下。可还是避免不了O(n^2)的时间复杂度。
后来看了别人的题解,感觉真是奇妙。

要找到当天结束时间最快的会议,我们可以运用一个小顶堆解决。这个堆是按结束时间从小到大排序的。或许更正式一点,小顶堆里存的是当天可参加的所有会议的结束时间。 很明显,我们只需要选择小顶堆的top会议即可。现在的任务是构建这个小顶堆。

首先,我们遍历起始时间 i,将当天开始的所有会议加进小顶堆中,并且将小顶堆里已经“过期” (结束时间 < 当天) 的会议剔除掉。然后,参加小顶堆的top会议即可。

现在还有一个问题,就是通过 O(1) 获取某天开始的所有会议。 我们可以很自然的想到这需要一个 时间 -> 会议 映射。你可以创建一个起始时间桶,也可以用一个map, 这个容易处理。因为我们遍历起始时间需要从 1 - 10^5,空间很密集,桶比map更合适一些。

class Solution {
public:
    int maxEvents(vector<vector<int>>& events) {
        const int MAX = 1e5+5;
        int ans = 0;
        vector<int> btn[MAX];    //起始时间桶
        for(int i = 0;i < events.size();i++)	//起始时间 -> 会议下标
        {
            btn[events[i][0]].push_back(i);
        }
        priority_queue<int,vector<int>,greater<int>> Q;
        for(int i = 1;i < MAX;i++)	//遍历起始时间
        {
            for(int j = 0;j < btn[i].size();j++)	//将该时间起始的所有会议按结束时间进堆
            {
                Q.push(events[btn[i][j]][1]);
            }
            while(!Q.empty() && Q.top() < i) Q.pop();	//剔除过期的会议
            if(!Q.empty()) Q.pop(), ans++;	//选距当前结束时间最短的会议
        }
        return ans;
    }
};

map做法:

class Solution {
public:
    int maxEvents(vector<vector<int>>& events) {
        const int MAX = 1e5+5;
        unordered_map<int,vector<int>> mp;  //用map会超时...emm...
        for(int i = 0;i < events.size();i++) 
        mp[events[i][0]].push_back(i);
        
        int ans = 0;
        priority_queue<int,vector<int>,greater<int>> Q;
        for(int i = 1;i < MAX;i++)
        {
            for(int j = 0;!mp[i].empty() && j < mp[i].size();j++)    //i时间开始的会议取结束时间全部加进小顶堆
            Q.push(events[mp[i][j]][1]);

            while(!Q.empty() && Q.top() < i) Q.pop();
            if(!Q.empty()) Q.pop(), ans++;
        }
        return ans;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值