今日頭條:任務調度面試題解答
題目:
產品經理(PM)有很多好的idea,而這些idea需要程序員實現。現在有N個PM,在某個時間會想出一個 idea,每個 idea 有提出時間、所需時間和優先等級。對於一個PM來說,最想實現的idea首先考慮優先等級高的,相同的情況下優先所需時間最小的,還相同的情況下選擇最早想出的,沒有 PM 會在同一時刻提出兩個 idea。
同時有M個程序員,每個程序員空閒的時候就會查看每個PM尚未執行並且最想完成的一個idea,然後從中挑選出所需時間最小的一個idea獨立實現,如果所需時間相同則選擇PM序號最小的。直到完成了idea纔會重複上述操作。如果有多個同時處於空閒狀態的程序員,那麼他們會依次進行查看idea的操作。
求每個idea實現的時間。
輸入第一行三個數N、M、P,分別表示有N個PM,M個程序員,P個idea。隨後有P行,每行有4個數字,分別是PM序號、提出時間、優先等級和所需時間。輸出P行,分別表示每個idea實現的時間點。
Java版的實現:
import lombok.Data;
import java.io.PrintStream;
import java.util.*;
public class TaskScheduler {
@Data
static class Task {
private int pmId;
private long createTime;
private int priority;
private long costTime;
private int workerId;
private long startTime;
private long finishTime;
}
static class PM {
Comparator<Task> samePMTaskComparator = (o1, o2) -> {
if (o1.priority > o2.priority) {
return -1;
} else if (o1.priority < o2.priority) {
return 1;
} else {
if (o1.costTime > o2.costTime) {
return -1;
} else if (o1.costTime < o2.costTime) {
return 1;
} else {
if (o1.createTime > o2.createTime) {
return -1;
} else if (o1.createTime < o2.createTime) {
return 1;
} else {
return 0;
}
}
}
};
PriorityQueue<Task> readyPriorityQueue = new PriorityQueue<>(samePMTaskComparator);
public void addTask(Task task){
readyPriorityQueue.add(task);
}
public Task peek() {
return readyPriorityQueue.peek();
}
public Task poll(){
return readyPriorityQueue.poll();
}
}
@Data
static class Programmer {
private int id;
private Comparator<Task> workTaskComparator = (o1, o2) -> (int) (o1.costTime - o2.costTime);
public Programmer(int id){
this.id = id;
}
public void onStart(Task task, long currentTime) {
if(task == null) {
return;
}
task.startTime = currentTime;
task.finishTime = task.startTime + task.costTime;
task.workerId = id;
}
public void onFinish(Task task) {
}
public Task selectTaskWithHighestPriority(PriorityQueue<Task> tasks){
if(tasks == null || tasks.size() == 0){
return null;
}
return tasks.poll();
}
}
private PM[] pms;
private Programmer[] programmers;
Map<Integer, Boolean> programmerFreeMap = new LinkedHashMap<>();
int n;//pm count
int m;//programmer count;
int p;//idea count
private Task[] startTimeSortedTasks;
public void init() {
pms = new PM[n];
for (int i = 0; i < n; i++) {
pms[i] = new PM();
}
programmers = new Programmer[m];
for (int i = 0; i < m; i++) {
programmerFreeMap.put(i, true);
programmers[i] = new Programmer(i);
}
}
public PriorityQueue<Task> getCandidateTasks() {
PriorityQueue<Task> workerCandidateTask = new PriorityQueue<>((o1, o2) -> o1.costTime != o2.costTime ? (int) (o1.costTime - o2.costTime) : o1.pmId - o2.pmId);
for (PM pm : pms) {
Task task = pm.peek();
if (task != null) {
workerCandidateTask.add(task);
}
}
return workerCandidateTask;
}
public void schedule(PrintStream print) {
//holder worker who will finish task firstly.
PriorityQueue<Task> workerPriorityQueue = new PriorityQueue<>((o1, o2 ) -> (int) (o1.finishTime - o2.finishTime));
int finish = 0;
int startTaskIndex = 0;
long currentTime = startTimeSortedTasks[0].createTime;
while (finish < p) {
//find all ready task.
while (startTaskIndex < p) {
Task task = startTimeSortedTasks[startTaskIndex];
//Task is ready to run
if (task.createTime <= currentTime) {
startTaskIndex++;
pms[task.pmId].addTask(task);
} else {
break;
}
}
PriorityQueue<Task> candidates = getCandidateTasks();
//schedule programmer to work
for (Programmer programmer:programmers) {
//programmer is free
if (programmerFreeMap.get(programmer.getId())) {
Task task = programmer.selectTaskWithHighestPriority(candidates);
if (task != null) {
programmerFreeMap.put(programmer.getId(), false);
programmer.onStart(task, currentTime);
workerPriorityQueue.add(task);
pms[task.pmId].poll();//poll task from ready task.
} else {
break;
}
}
}
//moving current time by finding first programmer that should finish his work in onStart or next created task.
if (!workerPriorityQueue.isEmpty()) {
Task task = workerPriorityQueue.peek();
if (startTaskIndex < p) {
Task nextTask = startTimeSortedTasks[startTaskIndex];
//task will be finished before next new task is created
if (task.finishTime <= nextTask.createTime) {
currentTime = task.finishTime;
workerPriorityQueue.poll();//remove finished task.
programmerFreeMap.put(task.workerId, true);//mark worker as free
print.println(task.pmId + ":" + task.finishTime);
finish += 1;
} else {
//task will be finished after new task is created, set current time creation time of next task.
currentTime = nextTask.createTime;
}
}
} else {
//no programmer is working , setting current time to creating of next task.
if (startTaskIndex < p) {
Task nextTask = startTimeSortedTasks[startTaskIndex];
currentTime = nextTask.createTime;
}
}
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
TaskScheduler scheduler = new TaskScheduler();
scheduler.n = scanner.nextInt();
scheduler.m = scanner.nextInt();
scheduler.p = scanner.nextInt();
List<Task> allTasks = new ArrayList<>();
for (int i = 0; i < scheduler.p; i++) {
Task task = new Task();
task.pmId = scanner.nextInt();
task.createTime = scanner.nextLong();
task.priority = scanner.nextInt();
task.costTime = scanner.nextLong();
allTasks.add(task);
}
//
Collections.sort(allTasks, (o1, o2)-> (int)(o1.createTime - o2.createTime));//按照createTime升序排列
scheduler.startTimeSortedTasks = allTasks.toArray(new Task[0]);
scheduler.init();
scheduler.schedule(System.out);
}
}