今日頭條:任務調度面試題解答

今日頭條:任務調度面試題解答

題目:

產品經理(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);
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章