最近,我接受了采访。我被要求设计一个会议日程安排程序,就像在Microsoft Outlook日历或gmail日历中一样。 我建议每天创建一个48的数组。每隔30分钟代表阵列入口。
我必须确保下一个约会不会与之前的会议发生冲突。
我的解决方案运行正常,但浪费了太多内存。
有谁能告诉我如何找到更好的解决方案来检测会议的碰撞。
我不知道一开始的所有会议。它们将在以后随机添加。
谢谢,
答案 0 :(得分:15)
从一个空的会议列表开始,每个会议都有一个start_time
和duration
。我们将按start_time
维护一个排序的会议列表。
要将会议添加到列表,请通过执行二进制搜索来查找列表中的所在位置。找到索引后,执行两次检查以避免冲突;在即将插入的会议之前和之后立即考虑会议(如果存在)。
start_time + duration
不超过新会议的start_time
。start_time+duration
不超过会后start_time
。如果断言得到满足,请将会议添加到列表中。
此添加操作需要O(log(list_size))
次。
注意:此方法假定添加具有重叠的会议是无效操作。如果允许存在重叠,则必须在新会议之前/之后的会议之外进行检查。
答案 1 :(得分:5)
我们可以使用树结构( BST )来存储请求(请求对象:开始时间/结束时间/日期/优先级等)。通过这样做,可以通过O(height_of_tree)实现添加/删除/搜索/更新操作。如果我们使用平衡树,我们可以获得优化的运行时间。对于上述每个操作, O(log n)。
这种方法比排序列表方法更好,因为在ArrayList的情况下,列表由固定大小的数组支持,其中O(n)用于将元素从旧数组复制到新数组。如果我们使用链表,则无法进行二进制搜索。
欢迎评论!
答案 2 :(得分:2)
这是我使用二进制搜索
插入的解决方案public class MeetingScheduler {
static class Meeting implements Comparable<Meeting> {
Date startTime;
Date endTime;
int duration;
public static final int MINUTE = 60000;
//duration in minutes
Meeting(Date startTime, int duration) {
this.startTime = startTime;
this.duration = duration;
this.endTime = new Date(startTime.getTime() + (MINUTE * duration));
}
@Override
public int compareTo(Meeting o) {
if (this.endTime.compareTo(o.startTime) < 0) {
return -1;
}//end time is before the other's start time
if (this.startTime.compareTo(o.endTime) > 0) {
return 1;
}////start time is after the other's end time
return 0;
}
@Override
public String toString() {
return "meeting {" +
"from " + startTime +
", minutes=" + duration +
'}';
}
}
private List<Meeting> meetings = new ArrayList<Meeting>();
public Meeting bookRoom(Meeting meeting) {
if (meetings.isEmpty()) {
meetings.add(meeting);
return null;
} else {
int pos = -Collections.binarySearch(meetings, meeting);
if (pos > 0) {
meetings.add(pos-1, meeting);
return null;
} else {
return meetings.get(-pos);
}
}
}
public List<Meeting> getMeetings() {
return meetings;
}
public static void main(String[] args) {
MeetingScheduler meetingScheduler = new MeetingScheduler();
Meeting[] meetingsToBook = new Meeting[]{
//October 3rd 2014
new Meeting(new Date(2014 - 1900, 10 - 1, 3, 15, 00), 15),
new Meeting(new Date(2014 - 1900, 10 - 1, 3, 16, 00), 15),
new Meeting(new Date(2014 - 1900, 10 - 1, 3, 17, 00), 60),
new Meeting(new Date(2014 - 1900, 10 - 1, 3, 18, 00), 15),
new Meeting(new Date(2014 - 1900, 10 - 1, 3, 14, 50), 10),
new Meeting(new Date(2014 - 1900, 10 - 1, 3, 14, 55), 10)
};
for (Meeting m : meetingsToBook) {
Meeting oldMeeting = meetingScheduler.bookRoom(m);
if (oldMeeting != null) {
System.out.println("Could not book room for " + m + " because it collides with " + oldMeeting);
}
}
System.out.println("meetings booked: " + meetingScheduler.getMeetings().size());
for (Meeting m : meetingScheduler.getMeetings()) {
System.out.println(m.startTime + "-> " + m.duration + " mins");
}
}
}
答案 3 :(得分:0)
虽然使用排序数组和二进制搜索是有效的,但请注意插入将采用o(n),假设没有发现冲突,因为阵列需要滑过会议。不确定这是否是最佳解决方案。
答案 4 :(得分:0)
如果排序列表是一个数组,我相信添加操作将采用O(n),因为你必须转移在即将插入会议之后开始的会议。