Problem description: Implement a MyCalendar
class to store your events. A new event can be added if adding the event will not cause a double booking.
Your class will have the method, book(int start, int end)
. Formally, this represents a booking on the half open interval [start, end)
, the range of real numbers x
such that start <= x < end
.
A double booking happens when two events have some non-empty intersection (ie., there is some time that is common to both events.)
For each call to the method MyCalendar.book
, return true
if the event can be added to the calendar successfully without causing a double booking. Otherwise, return false
and do not add the event to the calendar.
Your class will be called like this: MyCalendar cal = new MyCalendar();
MyCalendar.book(start, end)
题目描述:实现一个MyCalendar类,来存放事件。每当有新的事件添加时候,检测是否会导致冲突。
我想到的这个题的数据结构与LeetCode56 Merge Intervals 一样,就是一个list<interval>,按照start的顺序排列。要速度快,则需要实现二分查找。这个二分查找写的时候费了一些力气。
我二分查找的思路是:查找将来插入新的interval的位置,范围是从0到n(list的长度为n,index为0到n-1),当当前的位置mid的end <= 带插入的start,lo往右移动。因为之前没有冲突,则此时lo的index所指的位置就将是新插入的event的位置,可能是需要将新的event插入到此位置,也可能是将lo所指的位置和新的event连在一起。
class MyCalendar { class interval { int start; int end; public interval() {} public interval(int start, int end) { this.start = start; this.end = end; } } List<interval> list; public MyCalendar() { list = new ArrayList<>(); } public boolean book(int start, int end) { // for(int i = 0; i < list.size(); i++) { // System.out.print("[" + list.get(i).start + "," + list.get(i).end + "], "); // } // System.out.println(); if(end <= start) return true; //binary searcy if(list.size() == 0) { list.add(new interval(start, end)); return true; } int lo = 0, hi = list.size(); while(lo < hi) { int mid = (lo + hi) / 2; if(list.get(mid).end <= start) { lo = mid + 1; } else { hi = mid; } } // lo.end >= start //System.out.println(lo); if(lo == list.size() || list.get(lo).start >= end) { if(lo != list.size() && list.get(lo).start == end) { list.get(lo).start = start; } else { list.add(lo, new interval(start, end)); } return true; } return false; } }
这种写法较快,但是比较难想。
在discuss看到有shawn gao大神用TreeMap的解法,感觉很方便巧妙。用start作key,end作val。
class MyCalendar { TreeMap<Integer, Integer> calendar; public MyCalendar() { calendar = new TreeMap<>(); } public boolean book(int start, int end) { Integer floorKey = calendar.floorKey(start); if (floorKey != null && calendar.get(floorKey) > start) return false; Integer ceilingKey = calendar.ceilingKey(start); if (ceilingKey != null && ceilingKey < end) return false; calendar.put(start, end); return true; } }