前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LeetCode 1353. 最多可以参加的会议数目(排序+贪心,优先队列,难)

LeetCode 1353. 最多可以参加的会议数目(排序+贪心,优先队列,难)

作者头像
Michael阿明
发布2020-07-13 17:37:23
1.3K0
发布2020-07-13 17:37:23
举报

1. 题目

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

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

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

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
示例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

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/maximum-number-of-events-that-can-be-attended 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 解题

2.1 错误解

  • 先按会议的start排序,相同的话按照end排序
代码语言:javascript
复制
class Solution {//出错代码
public:
    int maxEvents(vector<vector<int>>& events) {
        sort(events.begin(), events.end(),[](const auto& a, const auto& b)
        		{
        			if(a[0] == b[0])
        				return a[1] < b[1];
        			return a[0] < b[0];
        		});
        int i, count = 0, attendTime = 0;
        for(i = 0; i < events.size(); ++i)
        {
        	if(attendTime < events[i][0])
        	{
        		attendTime = events[i][0];
        		count++;
        	}
        	else if(attendTime < events[i][1])
        	{
        		attendTime = attendTime+1;
        		count++;
        	}
        }
        return count;
    }
};
在这里插入图片描述
在这里插入图片描述

根据出错的例子,可知上面算法有缺陷: 正确的应该是:

  • 对当前会议i,还需要往下找到jj 被包含在i的区间内
  • 如果attendTime与区间j有交点,优先先参加j
在这里插入图片描述
在这里插入图片描述

2.2 超时解

代码语言:javascript
复制
class Solution {//超时代码
public:
    int maxEvents(vector<vector<int>>& events) {
        sort(events.begin(), events.end(),[](vector<int>& a, vector<int>& b)
        		{
        			if(a[0] == b[0])
        				return a[1] < b[1];
        			return a[0] < b[0];
        		});
        int i, j, count = 0, attendTime = 0;
        for(i = 0; i < events.size(); ++i)
        {
        	if(attendTime < events[i][0])
        	{
        		attendTime = events[i][0];
        		count++;
        		attendTime++;
        	}
        	else if(attendTime <= events[i][1])
        	{
        		for(j = i+1; j < events.size() && events[i][1] <= events[j][1]; ++j)
        			;
        		if(j < events.size() && attendTime >= events[j][0])
        		{
        			count++;
        			events.erase(events.begin()+j);
        			attendTime++;
        			i--;
        			continue;
        		}
                count++;
        		attendTime++;
        	}
        }
        return count;
    }
};

不幸的是:最后一个例子超时

在这里插入图片描述
在这里插入图片描述

2.3 通过解

优化

  • attendTimeevents[j]没有交点时,提前break
代码语言:javascript
复制
class Solution {//通过代码
public:
    int maxEvents(vector<vector<int>>& events) {
        sort(events.begin(), events.end(),[](vector<int>& a, vector<int>& b)
        		{
        			if(a[0] == b[0])
        				return a[1] < b[1];
        			return a[0] < b[0];
        		});
        int i, j, count = 0, attendTime = 0;
        for(i = 0; i < events.size(); ++i)
        {
        	if(attendTime < events[i][0])
        	{
        		attendTime = events[i][0];
        		count++;
        		attendTime++;//下一个可参加的时间
        	}
        	else if(attendTime <= events[i][1])//参加时间在区间内
        	{
        		for(j = i+1; j < events.size() && events[i][1] <= events[j][1]; ++j)
        		{	//向下查找,被i包含的区间j
        			if(attendTime < events[j][0])
        				break;//如果与attendTime没有交点,后面都不可能有
        		}
        		if(j < events.size() && attendTime >= events[j][0])
        		{	//如果有交点,优先参加j
        			count++;
        			events.erase(events.begin()+j);//参加了,删除掉
        			attendTime++;//下一个可能的参会时间点
        			i--;//后面会i++,先--i,继续跳转到原来的i进行处理
        			continue;
        		}
                count++;//attendTime与j没有交点,参加会议 i
        		attendTime++;//时间点往后挪一个
        	}
        }
        return count;
    }
};
在这里插入图片描述
在这里插入图片描述

2.4 大佬解

大佬的思路

  • 按照会议startevents 升序排序
  • 按日期time进行扫描
  • time时开始的会议都加入到优先队列(队列存储的是会议结束end时间)
  • 优先队列(小顶堆)把结束日期早的先出队,参加该会议
  • time++,新的一天,先把优先队列里已经过期的会议删除
代码语言:javascript
复制
class Solution {
public:
    int maxEvents(vector<vector<int>>& events) {
        sort(events.begin(), events.end());
        priority_queue<int,vector<int>, greater<int>> q;//小顶堆,结束时间早的,先出队
        int count = 0, i = 0, time = 0;
        while(i < events.size() || !q.empty())
        {
            time++;
            while(!q.empty() && q.top() < time)//结束时间过去了,该会议删除
                q.pop();
            while(i < events.size() && events[i][0] == time)
            {
                q.push(events[i][1]);//time时间,会议i开始了,把他的结束时间push进去
                i++;
            }
            if(!q.empty())
            {
                count++;
                q.pop();//最早结束的先参加
            }
        }
        return count;
    }
};
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-02-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 题目
  • 2. 解题
    • 2.1 错误解
      • 2.2 超时解
        • 2.3 通过解
          • 2.4 大佬解
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档