这里是题目描述:LeetCode-1353.最多可以参加的会议数目
贪心+优先队列解法
我们使用贪心原则:在某一天有多个可以参加的会议时,我们选择结束时间最早的来参加。
我们使用优先队列来存储当天可以参加的会议,优先级由会议结束时间来决定,保证可以在O(1)的时间开销内找到结束时间最早的会议并让它出队列,参加会议数+1;
那么,如何确定在某一天,哪些会议是可以参加的?我们事先对存储会议的数组以开始时间升序排列,在某一天时,就将所有以当天为开始时间的会议加入优先队,插入优先队列时间复杂度为O(logn);然后从队头清除结束时间早于当天但还没有被参加的会议;
至于优先队列如何来实现,我使用了java.util.PriorityQueue
,大家也可以尝试自己用堆来实现优先队列
java题解代码:
class Solution {
public int maxEvents(int[][] events) {
if(events.length<=1)
{
return events.length;
}
Event[] eventArr=new Event[events.length];
int eariest=events[0][0],latest=events[0][1];
for(int i=0;i<events.length;i++)
{
eventArr[i]=new Event(events[i][0],events[i][1]);
eariest=Math.min(eariest,events[i][0]);
latest=Math.max(latest,events[i][1]);
}
Arrays.sort(eventArr,new EventComparator()); //以开始时间升序排序
PriorityQueue<Event> canJoin=new PriorityQueue<>(); //存储可以参见的会议的优先队列,优先准则为会议结束时间,结束时间越早,优先级越高
int numJoin=0; //可以参加的会议数
int index=0;
for(int day=eariest;day<=latest;day++)
{
for(;index<eventArr.length;index++) //将当天开始的会议加入优先队列
{
if(eventArr[index].start<=day)
{
canJoin.offer(eventArr[index]);
}
else
{
break;
}
}
while(!canJoin.isEmpty()) //将在当天时已经结束的会议出队列
{
if(canJoin.peek().end<day)
{
canJoin.remove();
}
else
{
break;
}
}
if(!canJoin.isEmpty()) //从优先队列队头选取最早结束的会议出队列,参加会议数+1
{
canJoin.remove();
numJoin++;
}
}
return numJoin;
}
}
class Event implements java.lang.Comparable<Event> //定义会议类
{
int start;
int end;
Event(int start,int end)
{
this.start=start;
this.end=end;
}
@Override
public int compareTo(Event e) //以结束时间作为比较标准
{
return this.end-e.end;
}
}
class EventComparator implements java.util.Comparator<Event> //自定义的Event比较器
{
@Override
public int compare(Event e1,Event e2) //以开始时间作为比较标准
{
return e1.start-e2.start;
}
}
时间复杂度:排序和向优先队列插入所有元素O(nlogn),所有元素优先队列出队O(n),因此O(nlogn)
空间复杂度:O(n)