给你一个数组 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;
}
};