我正在尝试创建一个只使用python内置模块的调度函数,这些模块将返回最大数量的非重叠约会。函数的输入是列表列表,内部列表包含2个整数元素,即开始和结束时间。无法更改开始和结束时间,如果一次会议的开始时间与另一次会议的开始时间相同,则不会将其视为重叠。例如:
输入:
meetings = [[0, 1], [1, 2], [2, 3], [3, 5], [4, 5]]
max_meetings(meetings)
输出:
4
我现在使用的代码只是暴力破解它,并且在内存和执行时间方面都非常低效。尽管使用类很有趣,但似乎有更好的方法。
def max_meetings(meetings):
'''
Return the maximum number of non overlapping meeting that I can attend
input:
meetings - A list of lists. the inner list contains 2 values, the start
time[0] and the end time[1].
returns:
total - The total number of non overlapping meetings that I can attend.
'''
num_meetings = len(meetings)
assert (num_meetings <= 100)
appt_obj = [Appt(o) for o in meetings]
total = 0
for appt in appt_obj:
schedule = Schedule()
schedule.add_meeting(appt)
counter = 0
for comp_appt in appt_obj:
counter += 1
schedule.add_meeting(comp_appt)
# If there isnt a chance, break to save some time
if ((num_meetings - counter) < (total - schedule.meetings)):
break
if schedule.meetings > total:
total = schedule.meetings
return total
class Schedule:
'''
A class to hold my entire schedule. Can add
appointments
'''
def __init__(self):
self.times = set()
self.meetings = 0
def add_meeting(self, appt):
points = range(appt.start, appt.end)
if any(x in self.times for x in points):
pass
else:
# This for loop also seems unnecessary
for p in points:
self.times.add(p)
self.meetings += 1
class Appt:
'''
A class for an appointment
'''
def __init__(self, meeting):
assert (meeting[0] >= 0)
assert (meeting[1] <= 1000000)
self.start = meeting[0]
self.end = meeting[1]
答案 0 :(得分:1)
类通常运行速度稍慢但更容易理解;你的代码中的问题不是类,它是一个糟糕的算法(你可以编写一个超级优化的机器代码bubblesort并且它仍然会很慢)。
此问题非常适合动态编程:
按结束时间的升序排列所有会议
维护一个结束时间列表,例如lst[n] = t
,其中n
是会议次数,t
是可能的最早结束时间。让lst[0] = float("-inf")
作为无会议占位符。
要插入会议,找到n
的最低lst[n] <= start
,如果lst[n + 1]
不存在或大于end
,请{{1} }}
完成后,会议的最大数量为lst[n + 1] = end
。
根据您的示例,
len(lst) - 1
你最终应该
meetings = [[0, 1], [1, 2], [2, 3], [3, 5], [4, 5]]
应该被理解为“最多可以有1次会议结束1次,最多2次会议结束2次,最多3次会议结束3次,最多4次会议结束5次”。
请注意,这并不能告诉您会议的哪个组合会给出该结果,或者有多少这样的组合是可能的 - 只有至少存在一个这样的组合。
修改:尝试以下操作:
lst = [-inf, 1, 2, 3, 5]
像
一样运行from bisect import bisect
class Meeting:
# save about 500 bytes of memory
# by not having a __dict__
__slots__ = ("start", "end")
def __init__(self, start, end):
self.start = start
self.end = end
def __lt__(self, other):
return self.end < other.end
def max_meetings(meetings):
meetings.sort() # Meeting.__lt__ provides a natural sort order by meeting.end
# -1 is just a "lower than any actual time" gatepost value
lst = [-1]
for m in meetings:
# find the longest chain of meetings which this meeting can follow
i = bisect(lst, m.start)
if i == len(lst):
# new most-meetings value
lst.append(m.end)
elif m.end < lst[i]:
# new earliest finish-time for
lst[i] = m.end
# what is the most meetings we can attend?
# print(lst)
return len(lst) - 1
答案 1 :(得分:0)
如何在迭代中从原始列表中删除项目,然后只检查剩下的项目:
def overlaps(one, other):
if one[0] <= other[0] and other[1] <= one[1]:
return True
if other[0] <= one[0] and one[1] <= other[1]:
return True
else:
return False
def max_meetings(slots):
unique = 0
while len(slots) > 0:
meeting = slots.pop(0)
for slot in slots:
if overlaps(meeting, slot):
break
else:
unique +=1
return unique
meetings = [[0, 1], [1, 2], [2, 3], [3, 5], [4, 5]]
print(max_meetings(meetings))
如果存在overlaps
没有覆盖的边缘情况,那么您可以轻松地扩展逻辑,因为它在单独的函数中整齐地解耦。