时间调度问题的千层套路

2024-01-26 11:20

本文主要是介绍时间调度问题的千层套路,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

后台回复进群一起刷力扣

点击卡片可搜索关键词????

读完本文,可以去力扣解决如下题目:

252.会议室(Easy

253.会议室II(Medium

之前面试,被问到一道非常经典且非常实用的算法题目:会议室安排问题。

力扣上类似的问题是会员题目,你可能没办法做,但对于这种经典的算法题,掌握思路还是必要的。

先说下题目,给你输入若干形如[begin, end]的区间,代表若干会议的开始时间和结束时间,请你计算至少需要申请多少间会议室。

函数签名如下:

// 返回需要申请的会议室数量
int minMeetingRooms(int[][] meetings);

比如给你输入meetings = [[0,30],[5,10],[15,20]],算法应该返回 2,因为后两个会议和第一个会议时间是冲突的,至少申请两个会议室才能让所有会议顺利进行。

如果会议之间的时间有重叠,那就得额外申请会议室来开会,想求至少需要多少间会议室,就是让你计算同一时刻最多有多少会议在同时进行。

换句话说,如果把每个会议的起止时间看做一个线段区间,那么题目就是让你求最多有几个重叠区间,仅此而已。

对于这种时间安排的问题,本质上讲就是区间调度问题,十有八九得排序,然后找规律来解决。

题目延伸

我们之前写过很多区间调度相关的文章,这里就顺便帮大家梳理一下这类问题的思路:

第一个场景,假设现在只有一个会议室,还有若干会议,你如何将尽可能多的会议安排到这个会议室里?

这个问题需要将这些会议(区间)按结束时间(右端点)排序,然后进行处理,详见前文 贪心算法做时间管理。

第二个场景,给你若干较短的视频片段,和一个较长的视频片段,请你从较短的片段中尽可能少地挑出一些片段,拼接出较长的这个片段。

这个问题需要将这些视频片段(区间)按开始时间(左端点)排序,然后进行处理,详见前文 剪视频剪出一个贪心算法。

第三个场景,给你若干区间,其中可能有些区间比较短,被其他区间完全覆盖住了,请你删除这些被覆盖的区间。

这个问题需要将这些区间按左端点排序,然后就能找到并删除那些被完全覆盖的区间了,详见前文 删除覆盖区间。

第四个场景,给你若干区间,请你将所有有重叠部分的区间进行合并。

这个问题需要将这些区间按左端点排序,方便找出存在重叠的区间,详见前文 合并重叠区间。

第五个场景,有两个部门同时预约了同一个会议室的若干时间段,请你计算会议室的冲突时段。

这个问题就是给你两组区间列表,请你找出这两组区间的交集,这需要你将这些区间按左端点排序,详见前文 区间交集问题。

第六个场景,假设现在只有一个会议室,还有若干会议,如何安排会议才能使这个会议室的闲置时间最少?

这个问题需要动动脑筋,说白了这就是个 0-1 背包问题的变形:

会议室可以看做一个背包,每个会议可以看做一个物品,物品的价值就是会议的时长,请问你如何选择物品(会议)才能最大化背包中的价值(会议室的使用时长)?

当然,这里背包的约束不是一个最大重量,而是各个物品(会议)不能互相冲突。把各个会议按照结束时间进行排序,然后参考前文 0-1 背包问题详解 的思路即可解决,等我以后有机会可以写一写这个问题。

第七个场景,就是本文想讲的场景,给你若干会议,让你合理申请会议室。

好了,举例了这么多,来看看今天的这个问题如何解决。

题目分析

重复一下题目的本质:

给你输入若干时间区间,让你计算同一时刻「最多」有几个区间重叠

题目的关键点在于,给你任意一个时刻,你是否能够说出这个时刻有几个会议在同时进行?

如果可以做到,那我遍历所有的时刻,找个最大值,就是需要申请的会议室数量。

有没有一种数据结构或者算法,给我输入若干区间,我能知道每个位置有多少个区间重叠?

老读者肯定可以联想到之前说过的一个算法技巧:差分数组技巧。

把时间线想象成一个初始值为 0 的数组,每个时间区间[i, j]就相当于一个子数组,这个时间区间有一个会议,那我就把这个子数组中的元素都加一。

最后,每个时刻有几个会议我不就知道了吗?我遍历整个数组,不就知道至少需要几间会议室了吗?

举例来说,如果输入meetings = [[0,30],[5,10],[15,20]],那么我们就给数组中[0,30],[5,10],[15,20]这几个索引区间分别加一,最后遍历数组,求个最大值就行了。

还记得吗,差分数组技巧可以在 O(1) 时间对整个区间的元素进行加减,所以可以拿来解决这道题。

不过,这个解法的效率不算高,所以我这里不准备具体写差分数组的解法,参照 差分数组技巧 的原理,有兴趣的读者可以自己尝试去实现。

基于差分数组的思路,我们可以推导出一种更高效,更优雅的解法

我们首先把这些会议的时间区间进行投影:

红色的点代表每个会议的开始时间点,绿色的点代表每个会议的结束时间点。

现在假想有一条带着计数器的线,在时间线上从左至右进行扫描,每遇到红色的点,计数器count加一,每遇到绿色的点,计数器count减一:

这样一来,每个时刻有多少个会议在同时进行,就是计数器count的值,count的最大值,就是需要申请的会议室数量

对差分数组技巧熟悉的读者一眼就能看出来了,这个扫描线其实就是差分数组的遍历过程,所以我们说这是差分数组技巧衍生出来的解法。

代码实现

那么,如何写代码实现这个扫描的过程呢?

首先,对区间进行投影,就相当于对每个区间的起点和终点分别进行排序:

int minMeetingRooms(int[][] meetings) {int n = meetings.length;int[] begin = new int[n];int[] end = new int[n];// 把左端点和右端点单独拿出来for(int i = 0; i < n; i++) {begin[i] = meetings[i][0];end[i] = meetings[i][1];}// 排序后就是图中的红点Arrays.sort(begin);// 排序后就是图中的绿点Arrays.sort(end);// ...
}

然后就简单了,扫描线从左向右前进,遇到红点就对计数器加一,遇到绿点就对计数器减一,计数器count的最大值就是答案:

int minMeetingRooms(int[][] meetings) {int n = meetings.length;int[] begin = new int[n];int[] end = new int[n];for(int i = 0; i < n; i++) {begin[i] = meetings[i][0];end[i] = meetings[i][1];}Arrays.sort(begin);Arrays.sort(end);// 扫描过程中的计数器int count = 0;// 双指针技巧int res = 0, i = 0, j = 0;while (i < n && j < n) {if (begin[i] < end[j]) {// 扫描到一个红点count++;i++;} else {// 扫描到一个绿点count--;j++;}// 记录扫描过程中的最大值res = Math.max(res, count);}return res;
}

这里使用的是 双指针技巧,你可以认为指针 i 就是那根扫描线,根据i, j的相对位置就可以模拟扫描线前进的过程。

至此,这道题就做完了。当然,这个题目也可以变形,比如给你若干会议,问你k个会议室够不够用,其实你套用本文的解法代码,也可以很轻松解决。

接下来可阅读:

区间问题系列合集

_____________

学好算法靠套路,认准 labuladong,知乎、B站账号同名。公众号后台回复「微信」可加我好友,回复「目录」可获取文章分类:

这篇关于时间调度问题的千层套路的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/646635

相关文章

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

MySQL新增字段后Java实体未更新的潜在问题与解决方案

《MySQL新增字段后Java实体未更新的潜在问题与解决方案》在Java+MySQL的开发中,我们通常使用ORM框架来映射数据库表与Java对象,但有时候,数据库表结构变更(如新增字段)后,开发人员可... 目录引言1. 问题背景:数据库与 Java 实体不同步1.1 常见场景1.2 示例代码2. 不同操作

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

如何解决mysql出现Incorrect string value for column ‘表项‘ at row 1错误问题

《如何解决mysql出现Incorrectstringvalueforcolumn‘表项‘atrow1错误问题》:本文主要介绍如何解决mysql出现Incorrectstringv... 目录mysql出现Incorrect string value for column ‘表项‘ at row 1错误报错

如何解决Spring MVC中响应乱码问题

《如何解决SpringMVC中响应乱码问题》:本文主要介绍如何解决SpringMVC中响应乱码问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring MVC最新响应中乱码解决方式以前的解决办法这是比较通用的一种方法总结Spring MVC最新响应中乱码解

pip无法安装osgeo失败的问题解决

《pip无法安装osgeo失败的问题解决》本文主要介绍了pip无法安装osgeo失败的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 进入官方提供的扩展包下载网站寻找版本适配的whl文件注意:要选择cp(python版本)和你py

解决Java中基于GeoTools的Shapefile读取乱码的问题

《解决Java中基于GeoTools的Shapefile读取乱码的问题》本文主要讨论了在使用Java编程语言进行地理信息数据解析时遇到的Shapefile属性信息乱码问题,以及根据不同的编码设置进行属... 目录前言1、Shapefile属性字段编码的情况:一、Shp文件常见的字符集编码1、System编码

Spring MVC使用视图解析的问题解读

《SpringMVC使用视图解析的问题解读》:本文主要介绍SpringMVC使用视图解析的问题解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring MVC使用视图解析1. 会使用视图解析的情况2. 不会使用视图解析的情况总结Spring MVC使用视图