亚马逊访谈 - 设计会议日程安排

时间:2013-03-01 03:49:47

标签: algorithm

最近,我接受了采访。我被要求设计一个会议日程安排程序,就像在Microsoft Outlook日历或gmail日历中一样。 我建议每天创建一个48的数组。每隔30分钟代表阵列入口。

我必须确保下一个约会不会与之前的会议发生冲突。

我的解决方案运行正常,但浪费了太多内存。

有谁能告诉我如何找到更好的解决方案来检测会议的碰撞。

我不知道一开始的所有会议。它们将在以后随机添加。

谢谢,

5 个答案:

答案 0 :(得分:15)

从一个空的会议列表开始,每个会议都有一个start_timeduration。我们将按start_time维护一个排序的会议列表。

要将会议添加到列表,请通过执行二进制搜索来查找列表中的所在位置。找到索引后,执行两次检查以避免冲突;在即将插入的会议之前和之后立即考虑会议(如果存在)。

  1. 断言会前的start_time + duration不超过新会议的start_time
  2. 断言新会议start_time+duration不超过会后start_time
  3. 如果断言得到满足,请将会议添加到列表中。

    此添加操作需要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),因为你必须转移在即将插入会议之后开始的会议。