435. 无重叠区间(Python)

题目

难度:★★★☆☆
类型:数组
方法:动态规划,贪心算法

力扣链接请移步本题传送门
更多力扣中等题的解决方案请移步力扣中等题目录

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。

注意:

可以认为区间的终点总是大于它的起点。
区间 [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解决方案,请移步力扣中等题解析

你可能感兴趣的:(435. 无重叠区间(Python))