【贪心算法】力扣435:无重叠区间
给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。
示例:
输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。
思路1:贪心算法
在选择要保留区间时,区间的结尾十分重要:选择的区间结尾越小,余留给其它区间的空间就越大,就越能保留更多的区间。因此采取的贪心策略为:优先保留结尾小且不相交的区间。
具体实现方法:先把区间按照结尾的大小进行增序排序,每次选择结尾最小且和前一个选择的区间不重叠的区间。
注意:需要根据实际情况判断按区间开头排序还是按区间结尾排序
- 关于为什么是按照区间右端点排序?
这个题其实是预定会议的一个问题。给你若干时间的会议,然后去预定会议,那么能够预定的最大的会议数量是多少?核心在于我们要找到最大不重叠区间的个数。 如果我们把本题的区间看成是会议,那么按照右端点排序,我们一定能够找到一个最先结束的会议,而这个会议一定是我们需要添加到最终结果的的首个会议。(这个不难贪心得到,因为这样能够给后面预留的时间更长)。 - 关于为什么不能按照区间左端点排序?
同样地,我们把本题的区间看成是会议,如果“按照左端点排序,我们一定能够找到一个最先开始的会议”,但是最先开始的会议,不一定最先结束。
举例:
区间a是最先开始的,如果我们采用区间a作为放入最大不重叠区间的首个区间,那么后面我们只能采用区间d作为第二个放入最大不重叠区间的区间,但这样的话,最大不重叠区间的数量为2。但是如果我们采用区间b作为放入最大不重叠区间的首个区间,那么最大不重叠区间的数量为3,因为区间b是最先结束的。
作者:Chuancey
链接:https://leetcode-cn.com/problems/non-overlapping-intervals/solution/tan-xin-jie-fa-qi-shi-jiu-shi-yi-ceng-ch-i63h/
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
n = len(intervals)
if not intervals:
# if n == 0:
return 0
intervals.sort(key=lambda x: x[1]) # 根据对象中的第二维数据的值进行升序
right = intervals[0][1] # 从第一个区间的右端点开始进行比较
ans = 1 # 留下来的区间数,初始化为 1
for i in range(1, n):
# 后面区间的左端点依次与前面的右端点比较
if intervals[i][0] >= right:
ans += 1
right = intervals[i][1]
return n - ans
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/non-overlapping-intervals/solution/wu-zhong-die-qu-jian-by-leetcode-solutio-cpsb/
时间复杂度:O(nlogn),其中 n 是区间的数量。我们需要 O(nlogn) 的时间对所有的区间按照右端点进行升序排序,并且需要 O(n) 的时间进行遍历。由于前者在渐进意义下大于后者,因此总时间复杂度为 O(nlogn)。
空间复杂度:O(logn),即为排序需要使用的栈空间。
思路2:动态规划
题目的要求等价于「选出最多数量的区间,使得它们互不重叠」。由于选出的区间互不重叠,因此我们可以将它们按照端点从小到大的顺序进行排序,并且无论我们按照左端点还是右端点进行排序,得到的结果都是唯一的。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/non-overlapping-intervals/solution/wu-zhong-die-qu-jian-by-leetcode-solutio-cpsb/
由于该方法的时间复杂度较高,因此在下面的代码中,尽量使用列表推导优化常数,使得其可以在时间限制内通过所有测试数据。
class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
if not intervals:
return 0
intervals.sort()
n = len(intervals)
f = [1]
for i in range(1, n):
f.append(max((f[j] for j in range(i) if intervals[j][1] <= intervals[i][0]), default=0) + 1)
return n - max(f)
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/non-overlapping-intervals/solution/wu-zhong-die-qu-jian-by-leetcode-solutio-cpsb/
时间复杂度:O(n^2),其中 n 是区间的数量。我们需要 O(nlogn) 的时间对所有的区间按照左端点进行升序排序,并且需要 O(n^2) 的时间进行动态规划。由于前者在渐进意义下小于后者,因此总时间复杂度为 O(n^2)。
空间复杂度:O(n)。
注意到该方法本质上是一个最长上升子序列问题,因此我们可以将时间复杂度优化至 O(nlogn),具体可以参考「300. 最长递增子序列」。
【多人运动变种】穿上衣服我就不认识你了?来聊聊最长上升子序列
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理