我最近参加了一次采访,其中有人问我这个问题:
给定数组中的开始时间:[1, 2, 3, 2]
及其持续时间[3, 4, 4, 3]
查找并返回任务完成的顺序。对于此示例,结束时间为:[4, 6, 7, 5]
,因此返回的值应为[1, 3, 4, 2]
。
我的方法/解决方案:
创建一个数据结构,将每个类表示为具有以下属性的任务对象:
然后在每个对象的结束时间对数组进行排序。将每个元素与原始数组索引进行比较,并以原始任务顺序返回结束索引。
请建议任何更好的解决方案。在面试中使用这种方法很难实现(使用白板和标记)。如果没有更好的解决方案,最简单的方法是什么呢?更好的解决方案=更好的时间复杂性。
答案 0 :(得分:1)
让我们假设你有如下创建的原始集合(如数组)(显然是伪代码):
create collection first[] with elements (starttime, duration)
first.append (1, 3)
first.append (2, 4)
first.append (3, 4)
first.append (2, 3)
这为您提供了(starttime, duration)
元组first = [(1,3), (2,4), (3,4), (2,3)]
的集合。
然后,您可以使用仅包含两项内容的单独结构执行您想要的操作:
最初,填充此新结构second
的数组和数组,以使索引与原始数组first
匹配,如下所示:
create array second[] with elements (firstindex, endtime)
for each index in first.indexes:
second.append (index, first[index].starttime + first[index].duration)
这为您提供了(firstindex, endtime)
元组second = [(1,4), (2,6), (3,7), (4,5)]
的集合(我们假设这些集合是基于一个而不是从零开始)。
然后你继续根据结束时间排序 second
数组,给你second = [(1,4), (4,5), (2,6), (3,7)]
。
然后,您可以使用以下代码完成任务:
for each index in second.indexes:
output "task # ", second[index].firstindex
output " starts at, " first[second[index].firstindex].starttime
output " duration, " first[second[index].firstindex].duration
output " ends at ", second[index].endtime, new-line
输出结果为:
task # 1 starts at 1 duration 3 ends at 4
task # 4 starts at 2 duration 3 ends at 5
task # 2 starts at 2 duration 4 ends at 6
task # 3 starts at 3 duration 4 ends at 7
答案 1 :(得分:1)
免责声明:我的答案基于这样的想法,即如果没有任何排序就无法解决这个问题
诚实地说,您解决问题的方法听起来不错。该问题描述了结果应该是某种顺序,这意味着找不到比O(n log n)
更快的解决方案是有保证的。
这是因为众所周知,不存在可以对复杂度小于O(n log n)
的可排序元素列表进行排序的算法或程序。
这意味着如果您的解决方案在O(n log n)
中运行,那么您的解决方案就是最佳选择。如果我是你,我会在你的面试中提到你关于你的解决方案的这个属性,因为这表明你不仅明白你已经解决了问题,而且还知道不可能有一个更好的解决方案。
如果你必须实际执行此操作,只需练习几次。
答案 2 :(得分:0)
最简单,最快速的解决方案>
创建两个数组:
finaltime数组:[4, 6, 7, 5]
索引数组:[0,1,2,3]
使用quicksort对finaltime数组进行排序(或插入排序,如果可以肯定的话,数组将非常小=小于10个数字),每当切换最终时间数组元素时,也要切换索引数组。
当订购finaltime时,索引数组保存结果。
答案 3 :(得分:0)
您的解决方案听起来不错,但实际上您并不需要对象上的某些字段,也不需要自定义对象。
因为您已经专门为Java标记了它:
4294967264
答案 4 :(得分:0)
我创建了一个包含两个成员的任务对象,即开始时间和持续时间。任务对象有一个方法,根据开始时间和持续时间计算结束时间。
此外,我创建了一个任务比较器(见下文),它按结束时间比较两个任务。
然后主类创建这四个任务,将它们放入一个数组列表中,该列表使用上面创建的比较器进行排序。
课程任务:
public class Task {
private String m_name;
private double m_startTime;
private double m_duration;
...
public double calculateEndTime() {
return m_startTime + m_duration;
}
}
Class TaskComparator:
public class TaskComparator implements Comparator<Task>{
@Override
public int compare(Task t1, Task t2) {
if (t1 == null || t2 == null) {
return 0;
}
return Double.compare(t1.calculateEndTime(), t2.calculateEndTime());
}
主要方法:
public void go() {
List<Task> tasks = new ArrayList<Task>();
tasks.add(new Task("First Task", 1, 3));
tasks.add(new Task("Second Task", 2, 4));
tasks.add(new Task("Third Task", 3, 4));
tasks.add(new Task("Fourth Task", 2, 3));
Collections.sort(tasks, new TaskComparator());
for (Task task : tasks) {
System.out.println(task.toString());
}
}
答案 5 :(得分:0)
新版本 在Glubus评论之后,我明白我以前的解决方案并不像我想象的那么好。但为了精神错乱,我提出了一个新版本:
将相同位置分配给具有相同结束时间的任务
int[] calculateCompletionsOrder(int[] starttimes, int[] durations) {
// the key is the endtime (sorted ascending), the value is a list of the taskid with corresponding endtime
TreeMap<Integer, List<Integer>> set = new TreeMap<Integer, List<Integer>>();
// first iteration is needed to calucate endtimes
for (int taskId = 0; taskId < starttimes.length; taskId++) { // time complexity O(nlogn)
// calculate end time for the current task
int endtime = starttimes[taskId] + durations[taskId];
// add the task to the list of task with same end time
List<Integer> taskIds = set.get(endtime); // time complexity O(logn)
if (taskIds == null) {
taskIds = new ArrayList<Integer>();
set.put(endtime, taskIds); // time complexity O(logn)
}
taskIds.add(taskId); // time complexity O(1)
}
// now calculate the order each task get completed
int[] completionorders = new int[starttimes.length];
int order = 1;
// iterate over end times in ascending order
for (List<Integer> taskIds : set.values()) { // time complexity O(n)
for (int taskId : taskIds) {
// set the completion order for the selected task
completionorders[taskId] = order;
}
// increment order for next group of tasks with next end time
order++;
}
return completionorders;
}
每个插页都会分配排序成本。最终的复杂性是针对最佳,平均,最差的情况O(nlogn)。
旧版
问题是“查找并返回任务完成的顺序”。
这个问题没有说明如何表示订单。我的意思是:“如果你有四个元素,则应该从1到4之间的自然数表示”。
所以在我的解决方案中,顺序用整数表示(...,-3,-2,-1,0,1,2,3,...)。 “订单”也并不意味着两个数字是连续的。
输入:
算法(第一阶段):计算结束时间
max-end-time = 0;
for (int i = 0; i < start-time.length; ++i) {
end-time[i] = start-time[i] + durations[i];
max-end-time = max-end-time > end-time[i] ? max-end-time : end-time[i];
}
在第一阶段结束时,您的输出是:
算法(第二阶段):计算完成顺序
for (int i = 0; i < end-time.length; ++i) {
order[i] = end-time[i] - max-end-time;
}
在第二阶段结束时,完成顺序数组为:[ - 3,-1,0,-2]。
因此任务0是第一个,任务2是第三个,任务3是第四个,任务4是第二个,或者是另一个形式:[1,3,4,2]。
复杂性:如果n是算法执行的任务数n + n = 2n次迭代。所以这个算法是O(n)。