区间的元素选择
牛客网:挑选代表
题目描述
我们有很多区域,每个区域都是从a到b的闭区间,现在我们要从每个区间中挑选至少2个数,那么最少挑选多少个?
输入描述:
第一行是
N
N
N(
N
<
10000
N<10000
N<10000),表示有
N
N
N个区间,之间可以重复
然后每一行是
a
i
a_i
ai,
b
i
b_i
bi,持续
N
N
N行,表示现在区间。均小于100000
输出描述:
输出一个数,代表最少选取数量。
示例1
输入
4
4 7
2 4
0 2
3 6
输出
4
思路:
初次接触此题,还真没想到用贪心。自己掌握的不熟练,所以写博客激励自己,同时也方便以后的整理和查阅。
首先对于混乱的区间我们要排序,这里的排序针对的是区间右端点。排序之后的区间记做res,可以看做是右端点递增(或不减),这么做的好处是我们每次想添加新的点时,只需要考虑相邻区间即可。比如上面的例子排序后是
r
e
s
=
[
(
0
,
2
)
,
(
2
,
4
)
,
(
3
,
6
)
,
(
4
,
7
)
]
res=[(0,2),(2,4),(3,6),(4,7)]
res=[(0,2),(2,4),(3,6),(4,7)]
这里我们用sol存储合适的节点。对于节点的初始化,我们存储的是res首个区间的右端点-1,以及右端点。比如上面的例子,我们初始化sol就是
s
o
l
=
[
1
,
2
]
sol=[1,2]
sol=[1,2] 存储的这两个点是很有道理的,讲完整个过程你就明白了。
接下来我们开始遍历余下的每一个区间,每次都比较当前区间左端点与
s
o
l
[
−
1
]
sol[-1]
sol[−1] 的大小:
1 如果当前区间左端点==
s
o
l
[
−
1
]
sol[-1]
sol[−1],说明当前区间和上一个区间恰好相邻(接壤),那么此时的
s
o
l
sol
sol 需要再加入一个元素,自然就将当前区间的右端点加入进去。
2 如果当前区间左端点 >
s
o
l
[
−
1
]
sol[-1]
sol[−1],说明当前区间和上一个区间隔断了。那么此时的
s
o
l
sol
sol 必须加入当前区间内的两个点,所以
s
o
l
sol
sol 中就顺序添加当前区间的右端点-1,以及右端点。
3 其余情况都属于当前区间和上一个区间有交集,那么
s
o
l
sol
sol 不必再添加新的点,继续下一个区间遍历即可。
这里我们发现,
s
o
l
sol
sol 的最后一个元素其实就是当前遍历过的区间的最大元素,也是下一个区间是否添加端点的一个判断依据。而对于两个区间相离时,我们加入的右端点-1,和右端点,顺序一定不能混淆。原则就是加入的端点值在符合题意的情况下越大越好。
所以接着上面的例子分析,
s
o
l
=
[
1
,
2
,
4
]
sol=[1,2,4]
sol=[1,2,4],
s
o
l
=
[
1
,
2
,
4
,
6
]
sol=[1,2,4,6]
sol=[1,2,4,6]。因此最后输出sol的长度即可。而sol其实就是符合条件的答案中元素最大的一种方案。
代码借鉴了别人的,思路是自己琢磨的。创造源于抄袭哈!
def checkRes(num, nums):
sol = []
sol.append(nums[0][1]-1)
sol.append(nums[0][1])
for i in range(num-1):
if nums[i+1][0] == sol[-1]: #区间相邻
sol.append(nums[i+1][1])
elif nums[i+1][0] > sol[-1]:#区间相离
sol.append(nums[i+1][1]-1)
sol.append(nums[i+1][1])
return len(sol)
if __name__=='__main__':
n = int(input())
res = []
for _ in range(n):
res.append(list(map(int,input().split())))
res.sort(key=lambda x:x[1]) #区间排序
print(checkRes(n,res))