Program to find minimum time required to complete tasks with k time gap between same type tasks in Python

Suppose we have a list of integers called tasks where each item represents a different task type, and a non-negative integer k. Each task takes one unit of time to complete and tasks must be completed in the given order, but we must have k units of time between executing two tasks of the same type. At any time, we can either execute a task or wait. We need to find the minimum time required to complete all tasks.

For example, if tasks = [0, 1, 1, 2] and k = 2, the output will be 6. The first two tasks are different types, so they execute without gaps. At time 2, the next task is type 1 (same as previous), so we wait 2 time slots, then execute it, followed by task type 2. The execution sequence is: [0, 1, wait, wait, 1, 2], requiring 6 time slots total.

Algorithm Steps

To solve this problem, we follow these steps −

  • tick := 0 (current time)
  • slot := {} (dictionary to track when each task type can next be executed)
  • For each task t in tasks:
    • Get the earliest time this task type can be executed: tf := slot[t]
    • If tf exists and tf > tick, wait until that time: tick := tf
    • Execute the task: tick := tick + 1
    • Update when this task type can next be executed: slot[t] := tick + k
  • Return tick

Example

Let us see the following implementation to get better understanding −

def solve(tasks, k):
    tick = 0
    slot = {}
    
    for t in tasks:
        tf = slot.get(t)
        if tf is not None and tf > tick:
            tick = tf
        tick += 1
        slot[t] = tick + k
    
    return tick

tasks = [0, 1, 1, 2]
k = 2
print(solve(tasks, k))
6

How It Works

Let's trace through the example step by step −

def solve_with_trace(tasks, k):
    tick = 0
    slot = {}
    
    for i, t in enumerate(tasks):
        tf = slot.get(t)
        print(f"Task {i}: type {t}, current tick: {tick}")
        
        if tf is not None and tf > tick:
            print(f"  Must wait until tick {tf}")
            tick = tf
            
        tick += 1
        slot[t] = tick + k
        print(f"  Executed at tick {tick}, next available at tick {tick + k}")
        print(f"  Slot tracking: {slot}")
        print()
    
    return tick

tasks = [0, 1, 1, 2]
k = 2
result = solve_with_trace(tasks, k)
print(f"Total time required: {result}")
Task 0: type 0, current tick: 0
  Executed at tick 1, next available at tick 3
  Slot tracking: {0: 3}

Task 1: type 1, current tick: 1
  Executed at tick 2, next available at tick 4
  Slot tracking: {0: 3, 1: 4}

Task 2: type 1, current tick: 2
  Must wait until tick 4
  Executed at tick 5, next available at tick 7
  Slot tracking: {0: 3, 1: 7}

Task 3: type 2, current tick: 5
  Executed at tick 6, next available at tick 8
  Slot tracking: {0: 3, 1: 7, 2: 8}

Total time required: 6

Key Points

  • The algorithm maintains a dictionary slot to track when each task type can next be executed
  • If a task type was recently executed, we must wait k time units before executing it again
  • Tasks of different types can be executed immediately if no waiting is required
  • The time complexity is O(n) where n is the number of tasks

Conclusion

This algorithm efficiently calculates the minimum time needed to complete all tasks with the given constraints. It uses a greedy approach, executing tasks as soon as possible while respecting the cooldown period between same-type tasks.

Updated on: 2026-03-26T16:41:45+05:30

437 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements