题目
难度:★★★☆☆
类型:数组
方法:动态规划,贪心算法
力扣链接请移步本题传送门
更多力扣中等题的解决方案请移步力扣中等题目录
给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。
注意:
可以认为区间的终点总是大于它的起点。
区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。
示例
示例 1:
输入: [ [1,2], [2,3], [3,4], [1,3] ]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。
示例 2:
输入: [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
示例 3:
输入: [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。
解答
方法1:动态规划
这个题是【寻找最长上升子数组】的一个变体,有大佬对这个问题做过分析。
为了解决无重叠区间的问题,我们先将所有区间按照起点或者终点排序。
初始情况。这里,我们定义一个长度与输入数组intervals一致的dp数组,dp[i]表示intervals[0:i+1]这i个区间中,可以构成无重复区间的最长区间个数。
递推公式及其条件。我们需要从左到右遍历排序好了的所有区间,例如当前所考察的区间是intervals[i],而intervals[0:i]这些区间还需要逆序遍历,找出来一个区间intervals[j],如果可以满足intervals[i]和intervals[j]之间不存在重叠,那么可以考虑将dp[j]+1作为dp[i]的候选值,这里逆序的原因是为了减少寻找区间的次数,因为找到一个intervals[j]之后,在j左边的那些区间一定不会比intervals[j]更容易获取最长无重叠区间,就可以直接跳出当前i的循环了。
最后返回时,dp[-1]表示的是去除重叠区间后的最长无重叠区间的个数,所以需要同全部区间长度做差得到去除的区间个数。
class Solution:
def eraseOverlapIntervals(self, intervals) -> int:
if not intervals:
return 0
intervals.sort(key=lambda x: x[0])
dp = [1 for _ in range(len(intervals))]
for i in range(len(intervals)):
for j in range(i-1, -1, -1):
if intervals[j][1] <= intervals[i][0]:
dp[i] = max(dp[i], dp[j]+1)
break
return len(intervals) - dp[-1]
方法2:贪心算法
我们也可以用更高效的贪心算法来解决这个问题。
首先将区间按照左端点升序排列,然后从左到右考察每一对相邻区间:
如果区间i包含区间i+1,那么把最长的区间i去掉;
如果区间i和区间i+1存在交叉但不包含,则把后面一个区间i+1去掉。
及时统计去掉的区间个数。
class Solution:
def eraseOverlapIntervals(self, intervals):
res = 0
intervals = sorted(intervals, key=lambda x: x[0])
i = 0
while i < len(intervals) - 1:
if intervals[i][1] > intervals[i+1][0]: # 区间i和区间i+1存在交叉区域
if intervals[i][1] >= intervals[i+1][1]: # 区间i+1包含在区间i之内
intervals.pop(i) # 去除区间i
else: # 区间i+1不完全被区间i包含
intervals.pop(i+1) # 去除区间i+1
res += 1 # 被删除的区间数+1
else:
i += 1
return res
如有疑问或建议,欢迎评论区留言~
有关更多力扣中等题的python解决方案,请移步力扣中等题解析