我被要求为会议日程设计一个数据结构,然后合并它们。例如,如果人A从上午9:00到上午10:00开会,而人B在上午9:30到11:30开会,那么合并的忙时段是从上午9:00到11:30。
我为Person创建了类,这个类有会议对象的集合。 Meeting类具有24小时格式的开始时间[hh:mm],因此我可以轻松地进行比较。
class Person {
String name;
Collection<Meeting> meetings;
}
class Meeting{
int hh, mm;
int duration; // duration will be in minutes from where we can get the end time.
}
我想知道哪种数据结构对合并最有效。 一种方法是使用已排序的会议ArrayList。
任何更好的设计都值得赞赏。
答案 0 :(得分:2)
由于安排时间少于15分钟的会议是不现实的,我会满足于... long
。每天64位,足够16小时;我不需要那么多。或者,如果你愿意,可以使用两个长/三个整数。
然后合并是一个|
操作。对于较大的时隙,我可以移位 - 或者它们,然后检查未设置的位作为会议开始时间。这种高度压缩的数据结构只会因为低级操作而对任何索引产生影响。 CPU缓存可以适应数百天/用户的日程安排。
答案 1 :(得分:2)
由于@Anonymouse建议您可以使用96位,即12个字节来表示一天,因此从凌晨1点开始的30分钟会议将表示为110000,您可以使用简单的|对所有数字进行操作。
时间O(n)存储器O(12n)字节。理论上它会更快。
举行会议[分钟开始时间,分钟结束时间]。
重叠时将两个会议(Sa&amp; Sb)合并为Sc
Sc [minimum(SA-start,SB-start),maximum(SA-end,SB-end)]并将合并会议存储在集合中。如果没有重叠,那么您可以单独存储它们。
我们知道一天中的总分钟数= 24 * 60 = 1440 如果你有15分钟单位,那么它变成24 * 60/15 = 96(1字节以下)
因此,每个调度需要2个字节,即字节开始,结束。
时间O(n)存储器O(2n)字节
如果您以后必须删除会议,则这两种方法都不起作用。为此,您肯定会分别保留所有原始会议日程。
答案 2 :(得分:0)
在不合并时间表的情况下计算空闲时间:
这是我的方法:我不合并日历以计算空闲时间,而是使用TreeMap将繁忙的日程表标记为“ B”,将空闲时间标记为“ F”。我会在上下限内考虑每一分钟。最初,假设空闲时间可用于下限到上限,地图将更新为“ F”。稍后,地图将根据繁忙的时间表进行更新。因为间隔是一个列表,所以时间复杂度为O(n * 2),每个间隔都需要处理以更新地图。空间复杂度为O(n)。
ScheduleFinderTest test = new ScheduleFinderTest();
test.findFreeSchedules();
public class ScheduleFinderTest {
public void findFreeSchedules() {
// Employee availability time ( 9:00 to 12:00 )
MeetingIntervals bound = new MeetingIntervals(9, 00, 20, 00);
MeetingIntervals busyInterval1 = new MeetingIntervals(9, 00, 10, 30);
MeetingIntervals busyInterval2 = new MeetingIntervals(12, 00, 13, 00);
MeetingIntervals busyInterval3 = new MeetingIntervals(16, 00, 18, 00);
List<MeetingIntervals> allBusyIntervals1 = Arrays.asList(busyInterval1, busyInterval2, busyInterval3);
Employee e1 = new Employee("John", bound, allBusyIntervals1);
// Employee availability time ( 10:00 to 18:30 )
bound = new MeetingIntervals(10, 00, 18, 30);
busyInterval1 = new MeetingIntervals(10, 00, 11, 30);
busyInterval2 = new MeetingIntervals(12, 30, 14, 30);
busyInterval3 = new MeetingIntervals(14, 30, 15, 00);
MeetingIntervals busyInterval4 = new MeetingIntervals(16, 00, 17, 00);
List<MeetingIntervals> allBusyIntervals2 = Arrays.asList(busyInterval1, busyInterval2, busyInterval3, busyInterval4);
Employee e2 = new Employee("Christiana", bound, allBusyIntervals2);
ScheduleFinder scheduleFinder = new ScheduleFinder(Arrays.asList(e1, e2));
scheduleFinder.find();
}
}
@Data
@AllArgsConstructor
class Employee {
private String name;
private MeetingIntervals bounds;
private List<MeetingIntervals> intervals;
}
@Data
@AllArgsConstructor
class MeetingIntervals {
private int fromHour;
private int fromMinutes;
private int toHour;
private int toMinutes;
}
public class ScheduleFinder {
private List<Employee> employees;
public ScheduleFinder(List<Employee> employees) {
this.employees = employees;
}
public void find() {
// sort all bound hours (from availability) and get the maximum one
Collections.sort(employees, (e1, e2) -> e2.getBounds().getFromHour() - e1.getBounds().getFromHour());
int inTimeHour = employees.get(0).getBounds().getFromHour();
int inTimeMinutes = employees.get(0).getBounds().getFromMinutes();
// sort all bound hours ( to availability ) and get the minimum one
Collections.sort(employees, (e1, e2)-> e1.getBounds().getToHour() - e2.getBounds().getToHour());
int exitTimeHour = employees.get(0).getBounds().getToHour();
int exitTimeMinutes = employees.get(0).getBounds().getToMinutes();
// initially mark the map with free time for bounds as calculated above
MeetingIntervals availableInterval = new MeetingIntervals(inTimeHour, inTimeMinutes, exitTimeHour, exitTimeMinutes);
Map<String, Character> scheduleMap = new TreeMap<>();
updateSchedule(availableInterval, scheduleMap, 'F');
System.out.println(scheduleMap);
// update the map with busy intervals
List<MeetingIntervals> allBusyIntervals = employees.stream()
.flatMap(m -> m.getIntervals().stream())
.collect(Collectors.toList());
Collections.sort(allBusyIntervals, (e1, e2) -> e1.getFromHour() - e2.getFromHour());
updateScheduleMap(allBusyIntervals, scheduleMap, 'B');
System.out.println(scheduleMap);
// print free schedules
printFreeSchedules(scheduleMap, exitTimeHour, exitTimeMinutes);
}
private void updateScheduleMap(List<MeetingIntervals> busyIntervals, Map<String, Character> scheduleMap, char marker) {
for (MeetingIntervals interval : busyIntervals) {
updateSchedule(interval, scheduleMap, marker);
}
}
private void updateSchedule(MeetingIntervals interval, Map<String, Character> map, char marker) {
int startTimeHour = interval.getFromHour();
int startTimeMinutes = interval.getFromMinutes();
int startTimeInMinutes = getTimeInMinutes( startTimeHour, startTimeMinutes);
int endTimeInMinutes = getTimeInMinutes( interval.getToHour(), interval.getToMinutes());
for (int i = 0; i < (endTimeInMinutes - startTimeInMinutes); i++) {
String key = getFormattedKey(startTimeHour, startTimeMinutes);
if (marker == 'B' && map.get(key) != null) {
map.put(key, marker);
} else if (marker == 'F' && map.get(key) == null) {
map.put(key, marker);
}
++startTimeMinutes;
if (startTimeMinutes == 60) {
startTimeMinutes = 0;
++startTimeHour;
}
}
}
private int getTimeInMinutes(int hour, int minutes) {
return ( hour * 60 ) + minutes ;
}
public String getFormattedKey(int hour, int minutes) {
StringBuilder sb = new StringBuilder();
String hourStr = hour + "";
String minutesStr = minutes + "";
if (String.valueOf(hour).length() == 1) {
hourStr = "0" + hour;
}
if (String.valueOf(minutes).length() == 1) {
minutesStr = "0" + minutes;
}
sb.append(hourStr).append("h:").append(minutesStr).append("m");
return sb.toString();
}
private void printFreeSchedules(Map<String, Character> scheduleMap, int exitTimeHour, int exitTimeMinutes) {
boolean intervalStarted = false;
boolean intervalEnded = false;
for(String k : scheduleMap.keySet()) {
if ( scheduleMap.get(k) == 'F' && intervalStarted == false) {
System.out.print("[" + k);
intervalStarted = true;
intervalEnded = false;
}
if ( scheduleMap.get(k) == 'B' && intervalStarted == true && intervalEnded == false) {
System.out.println(" - " + k + "]");
intervalEnded = true;
intervalStarted = false;
}
}
if ( intervalStarted == true && intervalEnded == false ) {
System.out.println(" - " + exitTimeHour + "h:" + exitTimeMinutes + "m]");
}
}
}
答案 3 :(得分:-1)
这是Task Scheduling的经典问题。