0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

时间调度问题的千层套路

算法与数据结构 来源:labuladong 作者:labuladong 2022-08-08 14:14 次阅读

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

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

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

函数签名如下:

//返回需要申请的会议室数量
intminMeetingRooms(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) 时间对整个区间的元素进行加减,所以可以拿来解决这道题。

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

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

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

208311d6-16c9-11ed-ba43-dac502259ad0.jpg

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

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

20943a06-16c9-11ed-ba43-dac502259ad0.jpg

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

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

代码实现

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

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

20aa2898-16c9-11ed-ba43-dac502259ad0.jpg

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

//...
}

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

intminMeetingRooms(int[][]meetings){
intn=meetings.length;
int[]begin=newint[n];
int[]end=newint[n];
for(inti=0;i< n; i++) {
        begin[i] = meetings[i][0];
end[i]=meetings[i][1];
}
Arrays.sort(begin);
Arrays.sort(end);

//扫描过程中的计数器
intcount=0;
//双指针技巧
intres=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);
}

returnres;
}

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

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

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 算法
    +关注

    关注

    23

    文章

    4438

    浏览量

    90552
  • 数组
    +关注

    关注

    1

    文章

    406

    浏览量

    25580

原文标题:时间调度问题的千层套路

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    FreeRTOS任务调度器的三种调度算法讲解(下)

    配置如下时,调度算法就会变成不带时间片的抢占式调度
    的头像 发表于 03-21 13:46 482次阅读
    FreeRTOS任务<b class='flag-5'>调度</b>器的三种<b class='flag-5'>调度</b>算法讲解(下)

    元器件造假新套路:将“木马”嵌入到 FPGA 或内存组件中

    元器件造假新套路:将“木马”嵌入到 FPGA 或内存组件中
    的头像 发表于 12-07 11:40 184次阅读

    什么是Linux进程调度

    1、背景知识 1.1 什么是调度器 通常来说,操作系统是应用程序和可用资源之间的媒介。 典型的资源有内存和物理设备。但是CPU也可以认为是一个资源,调度器可以临时分配一个任务在上面执行(单位是时间
    的头像 发表于 11-09 09:05 240次阅读
    什么是Linux进程<b class='flag-5'>调度</b>器

    嵌入式系统中时间片的任务调度方式的优点是什么?

    嵌入式系统中时间片的任务调度方式的优点是什么
    发表于 10-20 06:48

    请问时间调度和定时器有什么区别?

    时间调度和定时器有什么区别?
    发表于 10-16 15:09

    CDN调度策略介绍

    DNS 调度 基于请求端 local DNS 的出口 IP 归属地以及运营商的 DNS 调度。 DNS 调度的问题: DNS 缓存时间在 TTL 过期前是不会刷新的, 这样会导致节点异
    的头像 发表于 10-09 16:07 490次阅读

    RR轮询调度?Verilog是如何实现RR轮询调度的?

    在设计中,我们经常会用到RR(Round-Robin,RR)轮询调度,用于保证在一个时间段内的多个请求信号都能得到公平响应。
    的头像 发表于 09-28 09:55 2288次阅读
    RR轮询<b class='flag-5'>调度</b>?Verilog是如何实现RR轮询<b class='flag-5'>调度</b>的?

    Linux CFS虚拟时间

    **CFS调度算法:**摒弃固定时间片,采用进程权重值的比重来量化计算实际运行时间,并引入虚拟时间和真实时间的概念,真实
    的头像 发表于 07-31 11:11 352次阅读
    Linux CFS虚拟<b class='flag-5'>时间</b>

    CDN常见的调度类型有哪些

    CDN通过调度的方式,选择最优节点为终端网民提供加速服务,那么调度方式显得尤为重要。在实际运用中,一般会采用4种调度类型,分别是DNS调度、HttpDNS、边缘302
    的头像 发表于 06-28 15:31 1007次阅读
    CDN常见的<b class='flag-5'>调度</b>类型有哪些

    rtthread nano时间片轮转调度线程失败怎么办呢?

    1)我用cubemx生成的rtthread-nano的makefile工程,不同优先级的线程可以正常调度。但我用官网上给出的线程时间片轮转调度示例程序无法正常运行。 2)例程里面的thread1
    发表于 05-12 16:58

    Quartz任务调度基本实现原理

    Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。Quartz允许开发人员根据时间间隔来调度作业。它实现了作业和触发器的
    的头像 发表于 04-12 10:48 678次阅读

    智能调度模式是什么 智能调度的优缺点

    智能调度模式是一种通过先进的信息技术和智能算法实现电力系统智能化调度的方式。智能调度模式可以是中央调度模式,区域调度模式,分布式
    发表于 04-11 15:35 2746次阅读

    智能调度什么意思 智能调度指标

    智能调度是指通过先进的计算机技术和智能化管理系统,对电力系统中的发电、输电、配电等各个环节进行智能化调度管理,以实现电力系统的高效、安全、稳定运行和优质供电。
    发表于 04-11 15:10 1945次阅读

    智能车间调度综述

    ,其中,每个工件完工都需要经过一定的工序加工。各工序的加工时间已确定,并且每个工件必须按照工序的先后顺序加工,工件所 有工序只有唯一的加工机器。 调度任务是安排所有作业的加工顺序,在满足约束条件的同 时,使性能指标得到优
    发表于 04-11 10:52 0次下载
    智能车间<b class='flag-5'>调度</b>综述

    智能调度什么意思

    智能调度什么意思 智能调度intelligent scheduling又称基于知识的调度(knowledge-based scheduling),是人工智能和智能控制感兴趣的研究领域之一。现实
    发表于 04-10 17:34 724次阅读