《programming for the puzzled》第二章
题目描述:一个聚会不同的人抵达和离开的时间的列表,其中的时间是前闭后开的,即如果你在结束的时间点到达,也会错过这个人。你只有一个小时,找到最佳的参加聚会的时间,使得碰到的人最多。
以一个tuple列表来表示不同的人参加聚会时间区间。
sched = [(6, 8), (6, 12), (6, 7), (7, 8), (7, 10), (8, 9), (8, 10), (9, 12), (9, 10), (10, 11), (10, 12), (11, 12)]
先自己做一下吧。
1 | # coding:utf-8 |
用的穷举,两层循环。结果是9点去,可以碰到5个人。
再来看看作者的分析。思路跟我一样的,穷举。
1 | # 作者的第一个算法,也是穷举 |
运行结果跟我是一样的,几个要点。
输入的数据不能更改,因此用tuple。
那个工具函数是计算到目前为止的时间区间内能遇到的人数,貌似有重复计算的。
程序的问题:如果时间不是整数,而是任意时间,如果精确到分钟,遍历次数会膨胀60倍,如果到秒,微秒呢……考虑一个不依赖时间粒度的算法。
这个我就想不出来了,看作者的程序吧。
1 | # 处理更细的时间 |
可以处理更细的时间了,思路是将所有人的赴约计划看成一条时间线,我自己的赴约时间与他们的时间线重合则能与他们相遇。于是只要看时间点的起止就行了。
先根据日程取出时间区间的起止点,对这个列表排序,在找出赴约时间和能见到的最大人数。输入数据是浮点数而不是整数。
下面实现排序和选择函数
1 | # 对列表排序 |
排序用的是选择排序,排序完成以后进行选择,方法是挨个取出排序好的列表中的元素,如果是抵达时间,计数器加一,如果是离开时间,计数器减一,并记录当前的最大相遇人数和取到最大值时的时间(因为当取值最大时,一定只能是抵达时间而不是离开时间)。
这样只要对列表遍历一遍就行了,而不是像第一个算法那样遍历两遍。但是选择排序的时间复杂度还是O(n²)。用其它排序方法可以优化到O(nlogn)。
练习1.假如你非常忙,只能在[ystart, yend)时间段内参加聚会,求你能见到的最多的人数。
在chooseTime函数的判断力增加时间限制即可。
if rcount > maxcount and t[0] >= ystart and t[0] < yend:
练习2.另一个不依赖时间粒度的算法:依次检查每个参加者的时间区间,看这个参加者的到达时间在多少其它参加者的时间区间内。选择最多的那位参与者的抵达时间。
1 | # 练习2.另一种不依赖时间粒度的算法 |
练习3.设想用一个数字表示你有多想见一位嘉宾,用一个三维的tuple表示,如(6.0, 8.0, 3)表示Ta六点到,8点离开,你想见Ta的程度为3。修改程序,找到你的抵达时间,使得权重值最大化(而不是人数)。
1 | # 练习3,使自己见到的嘉宾权重最大 |
就是把原来记次的地方改成累加权重。输出的结果是在11点抵达,最大权重值为13。跟书中的结果一样。
本章完成。b站上的课程视频的中文字幕貌似是机器翻译的,还不如没有呢。
我发文章的三个地方,欢迎大家在朋友圈等地方分享,欢迎点“在看”。
我的个人博客地址:https://zwdnet.github.io
我的知乎文章地址: https://www.zhihu.com/people/zhao-you-min/posts
我的微信个人订阅号:赵瑜敏的口腔医学学习园地