【贪心】总结

区间问题

类似合并区间,最大重叠区间等等这类问题都可以用贪心来解决。
常用的方法是先根据左端点或右端点排序,再遍历一遍判断区间是否重叠,这里提供几种模板:
一般题目会给一个list[],里面的元素通常以list形式,包含一个左端点和一个右端点。

模板1

按照左端点升序排序,顺序遍历

# 输入: intervals = [[1,2], [2,3], [2,4],[1,4]]
# 第一步、排序,按照左端点升序排
intervals.sort()
# 第二步、定义初始区间,将第一个区间作为初始区间
left,right = intervals[0][0],intervals[0][1]
n = len(intervals)
k = 1
# 第三步、从左到右遍历,从下标为1开始
for i in range(1,n):
	# 当前区间左右端点
    l,r = intervals[i][0],intervals[i][1]
    # 如果当前区间与比较区间有重合
    if l<right:  # 具体有没有“=”,根据题意确定
        right = min(right,r)   # 更新比较区间的右端点,扩展比较区间的范围
    else:  # 当前区间与比较区间没有重叠
        k += 1             
        left,right = l,r      # 更新比较区间

我个人比较喜欢用这个模板,基本所有区间问题都能解决,其思路也比较简单:
因为按照左端点排序后,可以保证当前区间与上个区间相比一定是起点相同或向右错开的,那么这个时候只需要比较当前区间与上个区间的右节点的关系,判断有没有重叠部分,没有的话那就是两个区间了,有的话按照题目要求更新区间的范围:

模板2

按照左端点升序排序,再逆序遍历(或者是按照左端点降序排序,再顺序遍历)

intervals.sort(key=lambda x:x[0],reverse=True)
k = 1
left = intervals[0][0]
for i in range(1,n):
    l,r = intervals[i][0],intervals[i][1]
    if r<=left:
        k += 1
        left = l

比如【435.无重叠区间】输入是[[1,2], [2,3], [2,4],[1,4]]
降序排序后变成[[2, 3], [2, 4], [1, 2], [1, 4]],写成下面这种形式
2 3
2 4
1 2
1 4
因为左端点降序排序,保证了当前区间与上一区间左端点对齐或者左偏,因此只需要比较右端点,通过比较右端点与上一区间的左端点来判断是否重叠,其余不重叠,则更新比较的左端点。

模板3

按照右端点升序排序,再顺序遍历

intervals.sort(key=lambda x:x[1])
k = 1
right = intervals[0][1]
for i in range(1,n):
    l,r = intervals[i][0],intervals[i][1]
    if l>=right:
        k += 1
        right = r

总结

其实上述三个模板的意思都差不多,核心都是排序+判断是否重叠+更新。
模板二三更简单一些,因为只关心有重叠,而模板一还需要更新右端点的范围,多了一个步骤。具体使用哪种方法全看个人习惯,不好理解的话画图分析可以有效帮助理解~

猜你喜欢

转载自blog.csdn.net/LoveJSH/article/details/128679695
今日推荐