Task Scheduler Ii

Solution For Task Scheduler Ii

Problem Statement:

You want to build a house on an empty land which reaches all buildings in the shortest amount of distance. You can only move up, down, left and right. You are given a 2D grid of values 0, 1 or 2, where:

Each 0 marks an empty land which you can pass by freely.
Each 1 marks a building which you cannot pass through.
Each 2 marks an obstacle which you cannot pass through.

Solution:

Approach: BFS (Breadth First Search)

Firstly, we need to determine whether it is possible to reach all the buildings from any given land. To do this, we will perform BFS traversal starting from each 1. For each 1, we will determine the distances d[i][j][k] to all lands that it can reach.

We will also keep a count c[i][j] which counts the number of 1s that we can reach from any given land. If we find a land i,j that can reach less than all the buildings, then we cannot build the house there as some buildings will not be reachable.

Algorithm Steps:

  1. Initialize 3D distance array d[i][j][k], 2D reachability array c[i][j], and total building count buildings.
  2. Traverse through the 2D grid array:
    a. For each building do BFS of all reachable empty lands, updating distance array d.
    b. For each reachable empty land at distance d[i][j][k], increment reachability count for this land in c[i][j].
    c. Find the minimum distance to cover all buildings for each empty land point.
    d. Choose the minimum of the empty land points with the minimum distance.
  3. Return the minimum distance calculated in step 2(d).

Let’s implement this solution in Python.

Python Code:

class Solution:
def bfs(self, i, j, grid, d, bldgs):
# BFS traversal
q = [(i, j, 0)] visited = set()
while q:
i, j, steps = q.pop(0)
if (i, j) in visited or i < 0 or j < 0 or i >= len(grid) or j >= len(grid[0]) or grid[i][j] == 2:
continue
visited.add((i, j))
if grid[i][j] == 1: # Building
bldgs.add((i, j)) # Add as a reachable building
d[i][j].append(steps) # Add distance to distance array
q.append((i+1, j, steps+1))
q.append((i-1, j, steps+1))
q.append((i, j+1, steps+1))
q.append((i, j-1, steps+1))

def shortestDistance(self, grid: List[List[int]]) -> int:
    rows, cols = len(grid), len(grid[0])

    d = [[[] for _ in range(cols)] for _ in range(rows)] # 3D array to store distances from each building to each land point
    c = [[0] * cols for _ in range(rows)] # 2D array to store the number of buildings we can reach from each land point
    bldgs = set() # Set of all building coordinates

    # Traverse through the grid, BFS traversal from each building
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == 1:
                self.bfs(i, j, grid, d, bldgs)

    # Traverse through the distance array and update c (reachability array)
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == 0: # Reachable empty land
                for k in range(len(d[i][j])):
                    c[i][j] += 1 # Increment count of reachable buildings

    # Find minimum distance to cover all buildings
    minimum = float('inf')
    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == 0 and c[i][j] == len(bldgs): # Reachable empty land with all buildings reachable
                minimum = min(minimum, sum(d[i][j])) # Update minimum distance

    return -1 if minimum == float('inf') else minimum

Time Complexity: O(n^2 * m^2) where n = number of rows and m = number of columns. We do BFS traversal for each building for each land point. Each BFS has time complexity O(nm) as we traverse through the entire grid.

Space Complexity: O(nm(r + c)) where r = maximum number of reachable buildings from a single empty land and c = maximum number of distances from a single building. We store a 3D distance array d which has n * m * r elements, a 2D reachability array c which has n * m elements and a set of all the building coordinates.

Step by Step Implementation For Task Scheduler Ii

import java.util.*;
 
class Solution {
    public int leastInterval(char[] tasks, int n) {
        int[] map = new int[26];
        for (char c: tasks)
            map[c - 'A']++;
        PriorityQueue < Integer > queue = new PriorityQueue < > (26, Collections.reverseOrder());
        for (int f: map) {
            if (f > 0)
                queue.add(f);
        }
        int time = 0;
        while (!queue.isEmpty()) {
            int i = 0;
            List < Integer > temp = new ArrayList < > ();
            while (i <= n) {
                if (!queue.isEmpty()) {
                    if (queue.peek() > 1)
                        temp.add(queue.poll() - 1);
                    else
                        queue.poll();
                }
                time++;
                if (queue.isEmpty() && temp.size() == 0)
                    break;
                i++;
            }
            for (int l: temp)
                queue.add(l);
        }
        return time;
    }
}
class Solution:
    def leastInterval(self, tasks: List[str], n: int) -> int:
        # Create a list of task frequencies
        task_freqs = collections.Counter(tasks).values()
        
        # Sort the list in descending order
        task_freqs.sort(reverse=True)
        
        # Get the max frequency
        max_freq = task_freqs[0]
        
        # Calculate the number of idle slots needed
        # The idea is to have as many tasks with the max frequency as possible
        # in each interval, with at least one task.
        # For example, if the tasks are ["A","A","A","B","B","B"], and n = 2,
        # we can schedule them like this:
        # A -> B -> idle -> A -> B -> idle -> A -> B
        # There are 2 intervals (A, B) with 3 tasks each and 2 intervals with 1 idle slot each.
        # In total, we need n * (max_freq - 1) + (max_freq - 1) + 1 = 8 slots.
        idle_slots = n * (max_freq - 1)
        
        # Fill the idle slots with tasks
        # We can use the remaining tasks to fill the idle slots.
        # For example, if the tasks are ["A","A","A","B","B","B"], and n = 2,
        # we can schedule them like this:
        # A -> B -> idle -> A -> B -> idle -> A -> B
        # There are 2 intervals (A, B) with 3 tasks each and 2 intervals with 1 idle slot each.
        # In total, we need n * (max_freq - 1) + (max_freq - 1) + 1 = 8 slots.
        for freq in task_freqs[1:]:
            # If the current task frequency is less than the max frequency,
            # we can use it to fill the idle slots
            if freq < max_freq:
                idle_slots -= freq
        
        # If there are more tasks than idle slots, we need to add more slots
        if idle_slots < 0:
            return len(tasks) + idle_slots
        
        # Otherwise, we can return the original number of tasks
        return len(tasks)
var scheduleTask = function(tasks, n) {
    // TODO: your code here
    // create a map to store the frequency of each task
    let map = {};
    for (let t of tasks) {
        map[t] = (map[t] || 0) + 1;
    }
    // create an array of task frequencies
    let freqs = [];
    for (let key in map) {
        freqs.push(map[key]);
    }
    // sort the array in descending order
    freqs.sort((a, b) => b - a);
    // find the maximum number of task frequency
    let fmax = freqs[0];
    // calculate the idle slots needed for the most frequent task
    let idle = (fmax - 1) * (n + 1);
    // fill the idle slots with the next most frequent tasks
    for (let f of freqs) {
        if (f === fmax) break;
        idle -= Math.min(fmax - 1, f);
    }
    // if there are more tasks than idle slots, return the length of the tasks array
    return idle > 0 ? idle + tasks.length : tasks.length;
};
There are a total of n tasks you have to pick, labeled from 0 to n-1. Some tasks may have dependencies, for example, if task 0 depends on tasks 1, then you cannot pick task 0 first. 

You are given an array of integers nums, where nums[i] is the number of tasks that depends on task i. 

You should return the ordering of tasks you should pick to finish all tasks. 

If there is a task that can be done multiple times, you can pick it any number of times.



One possible solution is to use topological sort. We can represent the dependencies between the tasks as a directed graph, where each node represents a task and each edge represents a dependency. Then, a valid ordering of the tasks is equivalent to a topological ordering of the corresponding directed graph.

We can use a modified version of DFS to find a topological ordering of the graph. In each step of the DFS, we choose a node that has no remaining dependencies and add it to the ordering. We then delete that node and all of its edges from the graph. We repeat this process until there are no more nodes left in the graph.

If there is a cycle in the graph, then there is no valid ordering of the tasks. We can detect a cycle by keeping track of which nodes are currently in the middle of the DFS. If we ever try to visit a node that is already in the middle of the DFS, then we have detected a cycle.

def findOrder(self, numTasks, prerequisites):
    # Represent the dependencies between the tasks as a directed graph.
    graph = collections.defaultdict(list)
    for i, j in prerequisites:
        graph[j].append(i)
 
    # Keep track of which nodes are currently in the middle of the DFS.
    in_progress = set()
 
    # Keep track of the ordering of the tasks.
    ordering = []
 
    def dfs(node):
        if node in in_progress:
            # There is a cycle, so this ordering is invalid.
            return False
 
        in_progress.add(node)
        for dependency in graph[node]:
            if not dfs(dependency):
                return False
 
        # We can finish this task now that all of its dependencies have
        # been completed.
        in_progress.remove(node)
        ordering.append(node)
        return True
 
    for node in range(numTasks):
        if not dfs(node):
            # There is a cycle, so this ordering is invalid.
            return []
 
    return ordering
public class Solution {
    public int LeastInterval(char[] tasks, int n) {
        //Create a dictionary to store the count of each task
        Dictionary taskCount = new Dictionary();
        foreach(char task in tasks){
            if(!taskCount.ContainsKey(task)){
                taskCount.Add(task, 1);
            }
            else{
                taskCount[task]++;
            }
        }
        //Sort the dictionary in descending order of task count
        var sortedTaskCount = taskCount.OrderByDescending(x => x.Value);
        //Find the maximum task count
        int maxCount = sortedTaskCount.First().Value;
        //Find the number of tasks with the maximum count
        int maxCountTaskCount = sortedTaskCount.Where(x => x.Value == maxCount).Count();
        //Calculate the minimum intervals needed
        int intervals = (maxCount - 1) * (n + 1) + maxCountTaskCount;
        //If the calculated intervals is less than the total number of tasks, return the total number of tasks
        return intervals < tasks.Length ? tasks.Length : intervals;
    }
}
Scroll to Top

Top 100 Leetcode Practice Problems In Java

Get 30% Off Instantly!
[gravityforms id="5" description="false" titla="false" ajax="true"]