Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Program to schedule tasks to take smallest amount of time in Python
Suppose we have a list of values called tasks where each different value represents a different task type, and we also have a non-negative integer k. Each task takes one minute to complete, but we must wait k minutes between doing two tasks of the same type. At any time, we can be doing a task or waiting. We have to find the smallest amount of time it takes to complete all the tasks.
So, if the input is like tasks = [2, 2, 2, 3, 3, 2], k = 1, then the output will be 7, as the optimal ordering is [2, 3, 2, 3, 2, WAITING, 2].
Algorithm Steps
To solve this, we will follow these steps ?
Count frequency of all task types using Counter
Initialize answer = 0 and lastsize = 0
-
While tasks remain:
Store current number of task types in lastsize
Process up to (k+1) most common task types
Decrement count of each processed task
Remove task types with zero count
Add (k+1) to answer (time for one cycle)
Return ans + lastsize - (k+1) to adjust for the final cycle
Example
from collections import Counter
class Solution:
def solve(self, tasks, k):
c = Counter(tasks)
ans = 0
lastsize = 0
while c:
lastsize = len(c)
for x, _ in c.most_common(k + 1):
c[x] -= 1
if c[x] == 0:
del c[x]
ans += k + 1
return ans + lastsize - (k + 1)
# Test the solution
ob1 = Solution()
tasks = [2, 2, 2, 3, 3, 2]
k = 1
result = ob1.solve(tasks, k)
print(f"Minimum time to complete all tasks: {result}")
Minimum time to complete all tasks: 7
How It Works
The algorithm works by processing tasks in cycles. In each cycle, we can execute at most (k+1) different task types without violating the cooling period constraint. We always choose the most frequent tasks first to minimize idle time.
For the example [2, 2, 2, 3, 3, 2] with k=1:
Initial count: {2: 4, 3: 2}
Cycle 1: Execute tasks 2 and 3 ? {2: 3, 3: 1}, time += 2
Cycle 2: Execute tasks 2 and 3 ? {2: 2, 3: 0}, time += 2
Cycle 3: Execute task 2 twice ? {2: 0}, time += 2
Final adjustment: 6 + 1 - 2 = 7
Alternative Approach
Here's a more intuitive solution using a simple greedy approach ?
from collections import Counter
def schedule_tasks_simple(tasks, k):
if not tasks:
return 0
# Count frequency of each task type
task_count = Counter(tasks)
# Find the task with maximum frequency
max_freq = max(task_count.values())
# Count how many tasks have maximum frequency
max_count = sum(1 for freq in task_count.values() if freq == max_freq)
# Calculate minimum time needed
# Formula: (max_freq - 1) * (k + 1) + max_count
min_time = (max_freq - 1) * (k + 1) + max_count
# The answer is maximum of calculated time and total tasks
return max(min_time, len(tasks))
# Test the alternative approach
tasks = [2, 2, 2, 3, 3, 2]
k = 1
result = schedule_tasks_simple(tasks, k)
print(f"Minimum time using formula approach: {result}")
Minimum time using formula approach: 7
Comparison
| Approach | Time Complexity | Space Complexity | Best For |
|---|---|---|---|
| Simulation | O(n log n) | O(n) | Understanding the process |
| Mathematical Formula | O(n) | O(n) | Optimal performance |
Conclusion
The task scheduling problem can be solved efficiently using either simulation or mathematical formula. The key insight is that we need to distribute high-frequency tasks with adequate cooling periods between them. The formula approach provides optimal O(n) time complexity.
