贪心算法题目

区间的元素选择
牛客网:挑选代表

题目描述

我们有很多区域,每个区域都是从a到b的闭区间,现在我们要从每个区间中挑选至少2个数,那么最少挑选多少个?

输入描述:
第一行是 N N N N &lt; 10000 N&lt;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))

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值