题目描述
实现一个MyCalendar,要求添加的时间不能重复三次;给定类中有,构造函数:MyCalendar 和 book方法,其中book方法的入参是[start, end)。
示例1:
MyCalendar();
MyCalendar.book(10, 20); // returns true
MyCalendar.book(50, 60); // returns true
MyCalendar.book(10, 40); // returns true
MyCalendar.book(5, 15); // returns false
MyCalendar.book(5, 10); // returns true
MyCalendar.book(25, 55); // returns true
解决思路
方法一
可以使用暴力解法,提供2个List;其中一个存储冲突后的交集,另外一个存储实际传入的[start, end);
示例图如下:
加入[10, 20),没有冲突;
加入[50, 60),没有冲突;
加入[10, 40),有冲突, 求交集[10, 20),放入另外一个secondList中;
加入[5, 15),发现在secondList中有冲突,直接返回false;
加入[5, 10),没有冲突;
加入[25, 55),有冲突,求交集[25, 40),[50, 55)放入另外一个secondList中
代码实现如下:
import java.util.ArrayList;
import java.util.List;
class MyCalendarTwo1 {
List<int[]> firstList;
List<int[]> secondList;
public MyCalendarTwo1() {
firstList = new ArrayList<>();
secondList = new ArrayList<>();
}
public boolean book(int start, int end) {
for (int[] second : secondList) {
int s = second[0];
int e = second[1];
if (start >= s && end <= e) {
return false;
} else if (start <= s && end >= e) {
return false;
} else if (start >= s && start < e) {
return false;
} else if (end > s && end <= e) {
return false;
}
}
for (int[] first : firstList) {
int s = first[0];
int e = first[1];
// 考虑哪些部分要写入到second
if (start >= s && end <= e) {
secondList.add(new int[]{start, end});
} else if (start <= s && end >= e) {
secondList.add(new int[]{s, e});
} else if (start >= s && start < e) {
secondList.add(new int[]{start, e});
} else if (end > s && end <= e) {
secondList.add(new int[]{s, end});
}
}
firstList.add(new int[]{start, end});
return true;
}
public static void main(String[] args) {
MyCalendarTwo1 myCalendarTwo = new MyCalendarTwo1();
System.out.println(myCalendarTwo.book(10, 20));
System.out.println(myCalendarTwo.book(50, 60));
System.out.println(myCalendarTwo.book(10, 40));
System.out.println(myCalendarTwo.book(5, 15));
System.out.println(myCalendarTwo.book(5, 10));
System.out.println(myCalendarTwo.book(25, 55));
}
}
方法二
使用差分数组,解决上述问题,即每次记录start和end的值,start加1,end减1;每次book操作时,遍历结果集,如果结果集大于2,则返回false。
示例图:
在执行[5,15) 时,计算结果为3,原因5计算1次,10计算2次,总共3次,最终需要把这个数据删除。
具体代码实现:
import java.util.Map;
import java.util.TreeMap;
class MyCalendarTwo {
TreeMap<Integer, Integer> treeMap;
public MyCalendarTwo() {
treeMap = new TreeMap<>();
}
public boolean book(int start, int end) {
treeMap.put(start, treeMap.getOrDefault(start, 0) + 1);
treeMap.put(end, treeMap.getOrDefault(end, 0) - 1);
int sum = 0;
for (Map.Entry<Integer, Integer> entry : treeMap.entrySet()) {
sum += entry.getValue();
if (sum > 2) {
treeMap.put(start, treeMap.getOrDefault(start, 0) - 1);
treeMap.put(end, treeMap.getOrDefault(end, 0) + 1);
return false;
}
}
return true;
}
public static void main(String[] args) {
MyCalendarTwo myCalendarTwo = new MyCalendarTwo();
System.out.println(myCalendarTwo.book(10, 20));
System.out.println(myCalendarTwo.book(50, 60));
System.out.println(myCalendarTwo.book(10, 40));
System.out.println(myCalendarTwo.book(5, 15));
System.out.println(myCalendarTwo.book(5, 10));
System.out.println(myCalendarTwo.book(25, 55));
}
}
总结
从代码实现角度,第二种方法明显简单很多,不必考虑复杂的计算;从实际测试结果来看时间复杂度要大于第一种方法的,我个人更喜欢第二种解法。