在访谈博客中遇到了这个问题。根据{{1}}人(a - b) i.e., from 'a' to 'b'
格式的自由时间安排,打印所有n
参与者都可用的所有时间间隔。这就像一个日历应用程序,建议可能的会议时间。
n
请分享任何已知的最佳算法来解决此问题。
我正在考虑以下解决方案。
创建一个Example:
Person1: (4 - 16), (18 - 25)
Person2: (2 - 14), (17 - 24)
Person3: (6 - 8), (12 - 20)
Person4: (10 - 22)
Time interval when all are available: (12 - 14), (18 - 20).
个间隔,其中包含每个人的一个间隔。最初是currentList
。
在currentList = [4-16, 2-14, 6-8, 10-22]
中查找max_start
和min_end
,如果currentList
,请输出(max_start, min_end)
;更新max_start < min_end
中的所有时间间隔,使currentList
值为start
。从min_end
中删除min_end
的时区间隔,并将该人员列表中的下一个条目添加到currentList
。
如果在上一步中currentList
,请更新max_start >= min_end
中的所有时间间隔,使currentList
值为start
。如果对于任何时间间隔max_start
,i
,请将end > start
中的间隔替换为相应人员的下一个时间间隔。
基于上述想法,它将在给定示例中运行如下:
currentList
虽然我没有实现上述内容。我正在考虑使用min-heap和max-heap来获取最小值和最大值。但我担心更新起始值,因为更新堆可能会变得昂贵。
答案 0 :(得分:4)
一个起点,仍然要优化一点,可能是以下(代码在Python中)。
您有以下数据(动态清楚地创建allPeople
列表):
person_1 = ["4-16","18-24"]
person_2 = ["2-14","17-24"]
person_3 = ["6-8","12-20"]
person_4 = ["10-22"]
allPeople = [person_1, person_2, person_3, person_4]
您可能会创建一个包含当天所有时段的列表(例如["0-1", "1-2", "2-3", etc.]
,如下所示:
allTimeSlots = []
for j in range(0,24):
allTimeSlots.append(str(j) + "-" + str(j+1))
然后创建一个名为commonFreeSlots
的列表,该列表由每个人的空闲时段集合内的所有时间段组成:
commonFreeSlots = []
for j in range(0,len(allTimeSlots)):
timeSlotOk = True
for k in range(0,len(allPeople)):
person_free_slots = parseSlot(allPeople[k])
if allTimeSlots[j] not in person_free_slots:
timeSlotOk = False
break
if timeSlotOk:
commonFreeSlots.append(allTimeSlots[j])
请注意,函数parseSlot
只是获取字符串列表(例如"2-14","15-16"
)并返回每小时时段列表(例如["2-3","3-4","4-5" etc.]
)以使其与上面创建的每小时时段列表allTimeSlots
:
def parseSlot(list_of_slots):
result = []
for j in range(0,len(list_of_slots)):
start_time = int(list_of_slots[j].split("-")[0])
end_time = int(list_of_slots[j].split("-")[1])
k = 0
while (start_time + k) < end_time:
result.append(str(start_time+k) + "-" + str(start_time+k+1))
k += 1
return result
如果我运行上面的脚本,我会得到以下结果:
['12-13', '13-14', '18-19', '19-20']
当然,为了聚合小时数(并且使用['12-14','18-20']
而不是每小时版本),你仍然需要输出一些输出,但我认为这应该更容易。
上述解决方案应始终有效,但我不确定它是否最佳,它可能存在更好的解决方案。但既然你还没有分享任何尝试,我想你只是想要一些入门提示,所以我希望这个有所帮助。
答案 1 :(得分:2)
今天在一次采访中得到了这个。提出了O(N*logN)
解决方案。想知道是否有O(N)
个解决方案可用...
概述:将单个计划加入一个列表intervals
->按间隔的开始时间对其进行排序->如果相交则合并相邻的间隔->现在可以轻松返回可用性。
import unittest
# O(N * logN) + O(2 * N) time
# O(3 * N) space
def find_available_times(schedules):
ret = []
intervals = [list(x) for personal in schedules for x in personal]
intervals.sort(key=lambda x: x[0], reverse=True) # O(N * logN)
tmp = []
while intervals:
pair = intervals.pop()
if tmp and tmp[-1][1] >= pair[0]:
tmp[-1][1] = max(pair[1], tmp[-1][1])
else:
tmp.append(pair)
for i in range(len(tmp) - 1):
ret.append([tmp[i][1], tmp[i + 1][0]])
return ret
class CalendarTests(unittest.TestCase):
def test_find_available_times(self):
p1_meetings = [
( 845, 900),
(1230, 1300),
(1300, 1500),
]
p2_meetings = [
( 0, 844),
( 845, 1200),
(1515, 1546),
(1600, 2400),
]
p3_meetings = [
( 845, 915),
(1235, 1245),
(1515, 1545),
]
schedules = [p1_meetings, p2_meetings, p3_meetings]
availability = [[844, 845], [1200, 1230], [1500, 1515], [1546, 1600]]
self.assertEqual(
find_available_times(schedules),
availability
)
def main():
unittest.main()
if __name__ == '__main__':
main()
答案 2 :(得分:1)
我更喜欢采用基于设定的稍微不同的方法!我会让语言元素为我完成繁重的工作。你们已经弄清楚了,我正在做一个假设,即所有会议都是每小时进行一次,间隔时间为1小时。
def get_timeslots(i, j):
timeslots = set()
for x in range (i, j):
timeslots.add((x, x + 1))
return timeslots
if __name__ == "__main__":
allTimeSlots = get_timeslots(0, 24)
person1TimeSlots = get_timeslots(4, 16).union(get_timeslots(18, 24))
person2TimeSlots = get_timeslots(2, 14).union(get_timeslots(17, 24))
person3TimeSlots = get_timeslots(6,8).union(get_timeslots(12, 20))
person4TimeSlots = get_timeslots(10, 22)
print(allTimeSlots
.intersection(person1TimeSlots)
.intersection(person2TimeSlots)
.intersection(person3TimeSlots)
.intersection(person4TimeSlots))
答案 3 :(得分:0)
以下是该问题的JavaScript解决方案。它的复杂度为O(n ^ 3),但由于时间有限,因此可以认为n ^ 2
const person_1 = ['4-16', '18-24'];
const person_2 = ['2-14', '17-24'];
const person_3 = ['6-8', '12-20'];
const person_4 = ['10-22'];
const allPeople = [person_1, person_2, person_3, person_4];
function getFreeMeetingTime(allPeople) {
//get a range of time in a day.
// you can pass the min and max from the input if its not 0 to 24 hrs
const allTimeSlotsInDay = getAllTimeSlots();
let tempResult = [];
for (const person of allPeople) {
for (const time of person) {
for (let i = Number(time.split("-")[0]); i < Number(time.split("-")[1]); i++) {
const val = `${i}-${i + 1}`;
if (!tempResult.includes(val)) {
tempResult.push(val);
}
}
}
}
return allTimeSlotsInDay.filter(time => !tempResult.includes(time));
}
function getAllTimeSlots() {
const result = [];
for (let i = 0; i < 24; i = i+1) {
result.push(`${i}-${i + 1}`);
}
return result;
}
console.log(getFreeMeetingTime(allPeople));
//[ '0-1', '1-2']
您可以在下面的链接中查看详细的代码
答案 4 :(得分:0)
Dmitry的解决方案在大多数情况下都足够好,但是这是另外O(k * N)
的时间和O(k)
的额外空间,其中N是会议的数量,k是时隙的粒度。如果已知每个会议都是每小时一次,则k可以是24。如果每30分钟举行一次会议,则k可以是48。k可以一直上升到60 * 24(您的粒度是一天中的每一分钟) )。您还可以将k设为所有时间的GCD。
概述:创建一个称为A的k大小的布尔数组,其中每个索引对应于您的时间粒度的可用性。它从每个可用插槽开始。运行所有会议。将在A的会议开始时间和结束时间之间的索引设置为False。最后,A拥有每个人共有的空闲时隙。时间必须以分钟为单位,算法才能生效。
minutesInDay = 60 * 24
def minuteToString(time):
hour = str(int(time / 60))
minute = str(int(time % 60))
if len(hour) == 1:
hour = '0' + hour
if len(minute) == 1:
minute = '0' + minute
return hour + ':' + minute
def stringToMinute(time):
hour, minute = time.split(':')
return 60 * int(hour) + int(minute)
def availableTimeSlots(meetings, k):
freeTime = [True] * k
step = int(minutesInDay / k)
for meet in meetings:
for i in range(int(meet[0] / step), int(meet[1] / step)):
freeTime[i] = False
result = list()
openInterval = False
beg, end = 0, 0
for i, slot in enumerate(freeTime):
if not openInterval and slot:
openInterval = True
beg = i
elif openInterval and not slot:
openInterval = False
end = i
beg = minuteToString(beg * step)
end = minuteToString(end * step)
result.append((beg, end))
return result
def main():
p1 = [
('9:00', '10:30'),
('12:00', '13:00'),
('16:00', '18:00'),
]
p2 = [
('10:00', '11:30'),
('12:30', '14:30'),
('14:30', '15:00'),
('16:00', '17:00'),
]
p3 = [
('00:00', '8:00'),
('12:00', '14:00'),
('18:00', '24:00'),
]
meetings = [
list(map(stringToMinute, meeting)) for p in [p1, p2, p3]
for meeting in p
]
print(meetings)
print(availableTimeSlots(meetings, 48))
if __name__ == '__main__':
main()