当前位置: 首页 > 编程日记 > 正文

一份贪心算法区间调度问题解法攻略,拿走不谢

640?wx_fmt=jpeg

作者 | labuladong

来源 | labuladong(ID:labuladong)

【导读】什么是贪心算法呢?贪心算法可以认为是动态规划算法的一个特例,相比动态规划,使用贪心算法需要满足更多的条件(贪心选择性质),但是效率比动态规划要高。


比如说一个算法问题使用暴力解法需要指数级时间,如果能使用动态规划消除重叠子问题,就可以降到多项式级别的时间,如果满足贪心选择性质,那么可以进一步降低时间复杂度,达到线性级别的。


什么是贪心选择性质呢,简单说就是:每一步都做出一个局部最优的选择,最终的结果就是全局最优。注意哦,这是一种特殊性质,其实只有一小部分问题拥有这个性质。


比如你面前放着 100 张人民币,你只能拿十张,怎么才能拿最多的面额?显然每次选择剩下钞票中面值最大的一张,最后你的选择一定是最优的。

然而,大部分问题都明显不具有贪心选择性质。比如打斗地主,对手出对儿三,按照贪心策略,你应该出尽可能小的牌刚好压制住对方,但现实情况我们甚至可能会出王炸。这种情况就不能用贪心算法,而得使用动态规划解决,参见前文 动态规划解决博弈问题。


一、问题概述


言归正传,本文解决一个很经典的贪心算法问题 Interval Scheduling(区间调度问题)。给你很多形如[start,end]的闭区间,请你设计一个算法,算出这些区间中最多有几个互不相交的区间。


举个例子,intvs=[[1,3],[2,4],[3,6]],这些区间最多有两个区间互不相交,即[[1,3],[3,6]],你的算法应该返回 2。注意边界相同并不算相交。

这个问题在生活中的应用广泛,比如你今天有好几个活动,每个活动都可以用区间[start,end]表示开始和结束的时间,请问你今天最多能参加几个活动呢?


二、贪心解法

这个问题有许多看起来不错的解决思路,实际上都不能得到正确答案。比如说:

也许我们可以每次选择可选区间中开始最早的那个?但是可能存在某些区间开始很早,但是很长,使得我们错误地错过了一些短的区间。

或者我们每次选择可选区间中最短的那个?或者选择出现冲突最少的那个区间?这些方案都能很容易举出反例,不是正确的方案。

正确的思路其实很简单,可以分为以下三步:

  1. 从区间集合 intvs 中选择一个区间 x,这个 x 是在当前所有区间中结束最早的(end 最小)。

  2. 把所有与 x 区间相交的区间从区间集合 intvs 中删除。

  3. 重复步骤 1 和 2,直到 intvs 为空为止。之前选出的那些 x 就是最大不相交子集。


把这个思路实现成算法的话,可以按每个区间的end数值升序排序,因为这样处理之后实现步骤 1 和步骤 2 都方便很多:


640?wx_fmt=gif


现在来实现算法,对于步骤 1,由于我们预先按照end排了序,所以选择 x 是很容易的。关键在于,如何去除与 x 相交的区间,选择下一轮循环的 x 呢?

由于我们事先排了序,不难发现所有与 x 相交的区间必然会与 x 的end相交;如果一个区间不想与 x 的end相交,它的start必须要大于(或等于)x 的end:


640?wx_fmt=jpeg


下面看下代码:


640?wx_fmt=png


三、应用举例


下面举例几道 LeetCode 题目应用一下区间调度算法。


第 435 题,无重叠区间:


640?wx_fmt=png


我们已经会求最多有几个区间不会重叠了,那么剩下的不就是至少需要去除的区间吗?

int eraseOverlapIntervals(int[][] intervals) {	int n = intervals.length;	return n - intervalSchedule(intervals);	
}

第 452 题,用最少的箭头射爆气球:


640?wx_fmt=png


其实稍微思考一下,这个问题和区间调度算法一模一样!如果最多有n个不重叠的区间,那么就至少需要n个箭头穿透所有区间:


640?wx_fmt=jpeg


只是有一点不一样,在intervalSchedule算法中,如果两个区间的边界触碰,不算重叠;而按照这道题目的描述,箭头如果碰到气球的边界气球也会爆炸,所以说相当于区间的边界触碰也算重叠:


640?wx_fmt=jpeg


所以只要将之前的算法稍作修改,就是这道题目的答案:

int findMinArrowShots(int[][] intvs) {	// ...	for (int[] interval : intvs) {	int start = interval[0];	// 把 >= 改成 > 就行了	if (start > x_end) {	count++;	x_end = interval[1];	}	}	return count;	
}

这么做的原因也不难理解,因为现在边界接触也算重叠,所以start == x_end时不能更新区间 x。


本文终。对于区间问题的处理,一般来说第一步都是排序,相当于预处理降低后续操作难度。但是对于不同的问题,排序的方式可能不同,这个需要归纳总结,以后再写写这方面的文章。


(*本文为 AI科技大本营转载文章,转载请联系作者)


福利时刻



入群参与每周抽奖~

扫码添加小助手,回复:大会,加入福利群,参与抽奖送礼!

640?wx_fmt=jpeg

大会5折优惠票倒计时 1 天! 团购还享立减优惠,倒计时 1 天!此外,伯克利大学名师精髓课程移师北京。《动手学深度学习》作者、亚马逊首席科学家李沐线下亲授「深度学习实训营」,免费GPU资源,现场还将限量赠送价值85元的配套书籍一本,先到先得。原价1099元,限时专享CSDN 独家福利价199元识别海报二维码,即刻购票~

640?wx_fmt=jpeg

推荐阅读

  • 2019 AI ProCon日程出炉:Amazon首席科学家李沐亲授「深度学习」

  • 玩嗨的2亿快手“老铁”和幕后的极致视觉算法

  • 与旷视、商汤等上百家企业同台竞技?AI Top 30+案例评选等你来秀

  • 从不温不火到炙手可热:语音识别技术简史

  • 入门大爆炸式发展的深度学习,你先要了解这6个著名框架

  • 用Python的算法工程师们,编码问题搞透彻了吗?

  • Python冷知识,不一样的技巧带给你不一样的乐趣

  • 我是如何通过开源项目月入 10 万的?

  • 撬动百亿台设备,让物联网“造”起来!

  • 程序员离无人值班有多远?

640?wx_fmt=png

你点的每个“在看”,我都认真当成了喜欢

相关文章:

css:z-index

针对position: absolute;解决position:relative;z-index固定定位层级显示问题转载于:https://blog.51cto.com/13507333/2352775

折半查找函数(from 《The C Programming Language》)

该函数用于判定已排序的数组array中是否存在某个特定的值value。这里假定数组元素以升序排列,如果数组array中包含value,则函数返回value在array中的位置(介于0~n-1之间的一个整数);否则,该函数返回-1。 在…

C++中的explicit关键字介绍

C中的关键字explicit主要是用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换。类构造函数默认情况下声明为隐式的即implicit。隐式转换即是可以由单个实参来调用的构造函数定义了一个从形…

Redis的集群模式

集群 即使使用哨兵,此时的Redis集群的每个数据库依然存有集群中的所有数据,从而导致集群的总数据存储量受限于可用存储内存最小的数据库节点,形成木桶效应。由于Redis中的所有数据都是基于内存存储,这一问题就尤为突出了尤其是当使…

刚上线就报名2000人!8位大牛免费讲座,再不报名就满额了!

今年是CSDN的第20年,我们已经不再满足解决你的技术问题,还要帮你解决人生大事!为了让你飞黄腾达,我们特别邀请到了8位大牛老师进行直播,他们已经实现了成为技术总监、创业、财富自由的梦想,这场直播&#x…

排序算法之插入排序

插入排序一般分为直接插入排序和二分插入排序。一、直接插入排序:直接插入排序又可以分为前插和后插,不过虽然是这样分,只是寻找地点的方向不一样而已。“前插”就是从头开始找合适的位置,“后插”就是从后面开始找合适的位置。直…

C++中#error/assert/static_assert的区别及使用

C 语言支持可帮助您调试应用程序的三个错误处理机制:#error 指令、static_assert 关键字和 assert (CRT) 宏。所有的三种机制都会发出错误消息。#error可看做预编译期断言,甚至都算不上断言,仅仅能在预编译时显示一个错误信息,它能…

读完ACL 2019录取的30篇知识图谱论文,我发现了这5点趋势

作者 | Michael Galkin译者 | Freesia编辑 | 夕颜出品 | AI科技大本营(ID: rgznai100)【导读】近年来,自然语言处理领域中广泛应用的知识图谱(KGs)正在不断地吸引人们的目光,此次 ACL 2019 中的有关于知识图…

力扣(LeetCode)933

题目地址:https://leetcode-cn.com/probl...题目描述:写一个 RecentCounter 类来计算最近的请求。 它只有一个方法:ping(int t),其中 t 代表以毫秒为单位的某个时间。 返回从 3000 毫秒前到现在的 ping 数。 任何处于 [t - 3000, …

2013年10月1日C#随机数

最近开始接触C跟C#,总是有人说女生本来就不适合做程序,就连今天都听到有人这样跟我讲,不过呢没有关系,我相信男生不一定比女生厉害多少,就好像我身边就有一位男生就总是觉得我的程序比他好一点就是理所当然的&#xff…

C/C++中inline/static inline/extern inline的区别及使用

引入内联函数的目的是为了解决程序中函数调用的效率问题,也是用内联函数取代带参宏定义(函数传参比宏更加方便易用)inline关键字用来定义一个类的内联函数。在类体中和类体外定义成员函数是有区别的:在类体中定义的成员函数为内联…

RISC-V架构上的Debian和Fedora现状

RISC-V仍然是开源/Linux用户非常感兴趣的,因为它是免版税且完全开放的CPU架构。部分原因是由于缺乏经济实惠的RISC-V硬件,限制了开发人员在这种架构上的更多工作,Linux发行版支持的RISC-V状态各不相同,但近年来至少有所改善。在上…

字节跳动李航:自学机器学习,研究AI三十载,他说AI发展或进入平缓期

作者 | 夕颜出品 | AI科技大本营(ID:rgznai100)【导读】一阵凉风吹过人工智能,让这个曾是燥热的领域逐渐冷却下来,留下的是扎实地在做研究的人、机构、企业。先后在 NEC 公司中央研究所、微软亚洲研究院、华为诺亚方舟实验室从事和…

PC上安装MAC X Lion

PC上安装MACXLion网上关于如何在PC下安装MAC的文章已近不少了,但对于一些初学者在实践当中会遇到各种问题,以下视频资料为大家展示两种虚拟机安装MacOS。1.VmwareWorkstation在虚拟机中安装首先将插件装好(在远景上下载)&#xff…

C++中static_cast/const_cast/dynamic_cast/reinterpret_cast的区别和使用

C风格的强制转换较简单,如将float a转换为int b,则可以这样:b (int)a,或者bint(a)。 C类型转换分为隐式类型转换和显示类型转换。 隐式类型转换又称为标准转换,包括以下几种情况: (1)、算术转换&#x…

行为型模式:命令模式

LieBrother原文: 行为型模式:命令模式 十一大行为型模式之三:命令模式。 简介 姓名 :命令模式 英文名 :Command Pattern 价值观 :军令如山 个人介绍 : Encapsulate a request as an object,ther…

与旷视、商汤等上百家企业同台竞技?AI Top 30+案例评选等你来秀!

人工智能历经百年发展,如今迎来发展的黄金时期。目前,AI 技术已涵盖自然语言处理、模式识别、图像识别、数据挖掘、机器学习等领域的研究,在汽车、金融、教育、医疗、安防、零售、家居、文娱、工业等行业获得了令人印象深刻的成果。在各行业宣…

在CSS中定义a:link、a:visited、a:hover、a:active顺序

摘自:http://www.qianyunlai.com/post-2.html以前用CSS一直没有遇到过这个问题,在最近给一个本科同学做的项目里面。出现一些问题,搜索引擎查了一些网站和资料,发现很多人问到这个问题,给出的结果我试了试,…

C++中istream的使用

在项目中会经常用到读取一些配置数据,这些数据根据实际需要有可能会调整,如果将这些数据直接嵌入进代码中会非常不便,需要经常调整代码。将这些数据写入配置文件中然后在读入,如果需要调整,只需修改配置文件&#xff0…

手把手教你用Python模拟登录淘宝

作者 | 猪哥66来源 | 裸睡的猪(ID:IT--Pig)最近想爬取淘宝的一些商品,但是发现如果要使用搜索等一些功能时基本都需要登录,所以就想出一篇模拟登录淘宝的文章!看了下网上有很多关于模拟登录淘宝,但是基本都…

Python之机器学习K-means算法实现

一、前言: 今天在宿舍弄了一个下午的代码,总算还好,把这个东西算是熟悉了,还不算是力竭,只算是知道了怎么回事。今天就给大家分享一下我的代码。代码可以运行,运行的Python环境是Python3.6以上的版本&#…

C++中模板的使用

模板(Template)指C程序设计语言中的函数模板与类模板,是一种参数化类型机制。模板是C泛型编程中不可缺少的一部分。C templates enable you to define a family of functions or classes that can operate on different types of information.模板就是实现代码重用机…

php面试问答

结合实际PHP面试,汇总自己遇到的问题,以及网上其他人遇到的问题,尝试提供简洁准确的答案包含MySQL、Redis、Web、安全、网络协议、PHP、服务器、业务设计、线上故障、个人简历、自我介绍、离职原因、职业规划、准备问题等部分 GitHub: https:…

图解LSTM与GRU单元的各个公式和区别

作者 | Che_Hongshu来源 | AI蜗牛车 (ID: AI_For_Car)因为自己LSTM和GRU学的时间相隔很远,并且当时学的也有点小小的蒙圈,也因为最近一直在用lstm,gru等等,所以今天没事好好缕了一下,接下来跟着我一起区分并…

iphone越狱神器

前阵子刚刚换了iphone5,老婆的4就留给我了。一到手就决定越狱,无意中发现了一款越狱神器:爱思助手http://www.i4.cn/ 确实很好用转载于:https://blog.51cto.com/shanks/1306423

json11库的使用

JSON(JavaScript Object Notation)是一种轻量级的文本数据交换格式,易于让人阅读。同时也易于机器解析和生成。尽管JSON是Javascript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。JSON解析器和JSON库支持许…

覆盖10亿设备,月活2亿,快应用要取代App?

作者 | 伍杏玲 来源 | CSDN(ID:CSDNnews) 2017 年 1 月 9 日,微信小程序横空出世,紧接着支付宝小程序、百度智能小程序、今日头条小程序、12 大厂商联盟的快应用等布局小程序。自此,小程序迅速改变国内移…

跨域的四种方式

本文主要是关于跨域的几种方式,关于什么是跨域这里就不多说了,写这个也是为了记住一些知识点的。 一. jsonp jsonp的跨域方式很容易理解,页面的的每一个script标签浏览器都会发送get请求获取对应的文本资源,获取到了之后&#xff…

使用模式创建一个面向服务的组件中间件

引言 在本文中,您将了解面向服务的组件中间件在用于资源有限的语音设备时,在设计阶段所应用的模式。它涵盖了项目的问题上下文,并被看成是一组决定因素,是对相关体系结构远景的一个简要概括。您还会得到一份描述,其中介…

OpenCV代码提取:遍历指定目录下指定文件的实现

OpenCV 3.1之前的版本,在contrib目录下有提供遍历文件的函数,用起来比较方便。但是在最新的OpenCV 3.1版本给去除掉了。为了以后使用方便,这里将OpenCV 2.4.9中相关的函数给提取了出来,适合在Windows 64bits上使用。directory.hpp…