区间问题解法(贪心)

labuladong之贪心算法区间调度

关于区间相关这类问题,基本思路都是排序,然后找交集或者找合集。首先要做的是讨论区间之间的包含情况,都画出图,决定是end还是start排序。

1. 最多不相交区间

【题目描述】

n个开区间 ( a i , b i ) (a_i,b_i) (ai,bi)。选择尽量多个区间,使得这些区间两两不相交。

终点排序
  1. 按照终点从小到大排序,pre初始化为排序后第一个区间(end最小,对于end相同的多个区间,选择start最大的区间)
    加入结果集合
  2. 遍历区间集合,将pre与遍历到的当前区间cur比较,将会出现以下三种情况(因为已经按照end排序)
  3. 根据情况决定是否更新pre,然后将新的pre加入结果集合
    在这里插入图片描述
    可以看出,只有第一种情况需要更新pre=cur

如果每次遍历一个cur都要比较是三种情况中的哪一个比较麻烦,根据图示可以看出,只有第一种情况我们需要更新pre并加入结果结合,然后cur++;其余两种都不需要处理,只需要cur++
我们只要直接定位到第一种情况对应的区间即可:
满足pre.end<cur.start,就更新pre=cur,然后将pre加入结果集合

sort(intervals,key=lambda x:x[1])
pre=intervals[0]
for cur in intervals:
	if pre[1]<cur[0]:
		pre=cur
		ans.append(pre)

起点和终点排序的不同之处

,终点排序可以直接确定要加入结果集合的pre,即确定了pre就可以直接加入结果集合;起点排序需要先根据情况确定pre和cur是否加入结果,然后再更新pre。

起点排序
  1. 起点从小到大排序,pre初始化为排序后的第一个区间
  2. 然后遍历集合的过程中,将pre与遍历到的当前区间cur 比较,会出现以下三种情况
  3. 根据不同的情况,决定是否pre更新,以及pre和cur哪一个区间加入结果集合

pre(蓝色)和cur(绿色)的结果有以下三种:
在这里插入图片描述

case1:pre和cur都加入结果集合,pre=cur
case2:cur加入结果集合,pre=cur
case3:pre加入结果集合,pre不更新

sort(intervals,key=lambda x:x[0])
pre=intervals[0]
for cur in intervals:
	if pre[1]<cur[0]:
		ans.append(pre)
		ans.append(cur)
		pre=cur
	elif pre[0]<cur[0] and pre[1]>cur[1]:
		ans.append(cur)
		pre=cur
	else:
		ans.append(pre)
【例题】

1 无重叠区间
在这里插入图片描述

2.区间选点

【题目描述】

数轴上有n个闭区间 [ a i , b i ] [a_i,b_i] [ai,bi]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)

终点排序
  1. end排序,pre初始化为第一个(end最小)
  2. 点就取pre[1]的位置,cur用来遍历集合
  3. 只要是和pre有交集的区间,就都包含点了,直到遍历找到pre.end<cur.start,pre=cur,重复2(每次更新pre就确定一个点)
  4. 直到cur 遍历整个集合
起点排序

其实就是找尽量多个区间的交集,或者说,确定一个小区间([a,a])被尽量多的区间包含,如何确定?在遍历过程中不断找交集,缩小交集

  1. start排序,pre初始化为第一个(start最小)
  2. 用cur遍历集合
  3. 当pre合cur有交集的时候,更新pre区间(缩小) :pre[0]=max(pre[0] , cur[0]) pre[1]=min(pre[1] , cur[1])
  4. 当pre和cur没有交集的时候,点取在pre内即可(一般就缩小到一个点了pre[0]=pre[1]),然后更新pre=cur
  5. 直到遍历整个区间

点爆气球leetcode

3.区间覆盖

【问题描述】

给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间), 求最少使用多少条线段可以将整个区间完全覆盖 样例:
区间长度8,可选的覆盖线段[2,6],[1,4],[3,6],[3,7],[6,8],[2,4],[3,5]

起点排序
  1. 将每一个区间按照左端点递增顺序排列,排完序后为[1,4],[2,4],[2,6],[3,5], [3,6],[3,7],[6,8]
  2. 设置一个变量表示已经覆盖到的区域cover
  3. 再剩下的线段中找出所有左端点小于等于当前
    已经覆盖到的区域的右端点的线段中,右端点最大的线段在加入:
    cur遍历集合,找cover.end<cur.start所有满足的cur,选择end最大的cur,更新cover=cover U cur
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值