Task Scheduler with Prerequisites and Execution Paths
Problem statement
Build a task scheduler. It starts empty. Process operations in order; taskIds[i] and prerequisites[i] hold the values for operations[i].
Each task is waiting, running or completed. A task is ready when it is waiting and all of its prerequisites are completed.
"addTask": add a waiting tasktaskIds[i]whose prerequisites areprerequisites[i]. A task with no prerequisites is ready right away."getNextTask": hand out the ready task that was added earliest. It becomes running. Record a list with its id, or an empty list if no task is ready."completeTask": the running tasktaskIds[i]becomes completed. This can make other tasks ready."getExecutionPath": record the execution path for the target tasktaskIds[i]. This does not change any task.
The execution path holds the target and every task it depends on, directly or through other prerequisites, that is not completed yet. Running tasks are included. List them so that every task comes after its prerequisites: repeatedly take the task added earliest among those whose prerequisites are all completed or already listed. If the target is completed, the path is empty.
Return the recorded lists of all getNextTask and getExecutionPath operations, in order.
Function
runTaskScheduler(operations: String[], taskIds: String[], prerequisites: String[][]) → String[][]Examples
Example 1
operations = ["addTask","addTask","getNextTask","getNextTask","getNextTask"]taskIds = ["build","test","","",""]prerequisites = [[],[],[],[],[]]return = [["build"],["test"],[]]Part 1 has no prerequisites. getNextTask hands out build, then test, in the order they were added. The third call finds no waiting task and records an empty list.
Example 2
operations = ["addTask","addTask","addTask","getNextTask","getNextTask","getNextTask","completeTask","getNextTask"]taskIds = ["fetch","parse","lint","","","","fetch",""]prerequisites = [[],["fetch"],[],[],[],[],[],[]]return = [["fetch"],["lint"],[],["parse"]]parse needs fetch. The first call hands out fetch. The second call skips parse, because fetch is not completed yet, and hands out lint. The third call finds nothing ready and records []. After fetch is completed, parse is ready and is handed out.
Example 3
operations = ["addTask","addTask","addTask","addTask","getExecutionPath","getNextTask","completeTask","getExecutionPath"]taskIds = ["a","b","c","d","d","","a","d"]prerequisites = [[],["a"],["a"],["c","b"],[],[],[],[]]return = [["a","b","c","d"],["a"],["b","c","d"]]To run d, we need b and c, which both need a. In added order, the path is a, b, c, d. Then a is handed out and completed, so the second path leaves it out: b, c, d.
Constraints
1 <= operations.length <= 1000taskIds.length == prerequisites.length == operations.length- Each
operations[i]is"addTask","getNextTask","completeTask"or"getExecutionPath". - Task ids are 1 to 8 lowercase English letters, and no two
addTaskcalls use the same id. - For
addTask,prerequisites[i]has at most 5 different ids, and each one was added by an earlieraddTask. For every other operation,prerequisites[i]is empty. - For
getNextTask,taskIds[i]is the empty string. completeTaskis only called on a running task.getExecutionPathis only called on a task that was already added.