题目地址:
https://leetcode.com/problems/maximum-number-of-events-that-can-be-attended/description/
给出 n n n个活动的开始和结束日期(日期可以看成是数轴上的单位区间),一个人每天可以挑任意一个活动参加,他同一天不能同时参加多个活动。问他最多能参加多少个活动。同一个活动不同天参加也只算参加了 1 1 1次。
思路是贪心。将所有活动按开始时间从小到大排序,然后建立一个小顶堆,其存每个活动的结束时间,同时维护一个时间戳。这个时间戳可以视为一根扫描线,我们关注的是这个时间戳是否能参加某个活动,而堆顶则是我们优先要参加的活动(因为它结束的最早)。
如果活动没遍历完,或者堆里还有活动,则进入循环。首先将所有当前时间戳开始的活动的结束时间入堆,这个时候我们可以直接参加堆顶那个活动,将堆顶出堆。下一轮中所有结束时间在当前时间戳或之前的活动都不能参加了,于是将这些活动出堆,同时时间戳加一。循环完成之后返回答案即可。算法正确性证明还是比较显然的,如果某个时间戳参加的不是结束时间最早的,我们可以调换为参加那个结束时间最早的,也可以是最优解。
代码如下:
class Solution {
public:
int maxEvents(vector<vector<int>>& es) {
int n = es.size();
sort(es.begin(), es.end());
priority_queue<int, vector<int>, greater<int>> heap;
int res = 0;
for (int i = 0, cur = 0; i < n || heap.size();) {
// 如果堆里没有活动了,但还有活动可以参加,则直接将时间戳挪到接下来的活动的开始时间
if (heap.empty()) cur = es[i][0];
while (i < n && es[i][0] == cur) heap.push(es[i++][1]);
res++;
heap.pop();
// 把参加不了的活动删掉
while (heap.size() && heap.top() <= cur) heap.pop();
cur++;
}
return res;
}
};
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)。