You are given a 0-indexed integer array tasks
, where tasks[i]
represents the difficulty level of a task. In each round, you can complete either 2 or 3 tasks of the same difficulty level.
Return the minimum rounds required to complete all the tasks, or -1
if it is not possible to complete all the tasks.
Example 1:
Input: tasks = [2,2,3,3,2,4,4,4,4,4] Output: 4 Explanation: To complete all the tasks, a possible plan is: - In the first round, you complete 3 tasks of difficulty level 2. - In the second round, you complete 2 tasks of difficulty level 3. - In the third round, you complete 3 tasks of difficulty level 4. - In the fourth round, you complete 2 tasks of difficulty level 4. It can be shown that all the tasks cannot be completed in fewer than 4 rounds, so the answer is 4.
Example 2:
Input: tasks = [2,3,3] Output: -1 Explanation: There is only 1 task of difficulty level 2, but in each round, you can only complete either 2 or 3 tasks of the same difficulty level. Hence, you cannot complete all the tasks, and the answer is -1.
Constraints:
1 <= tasks.length <= 105
1 <= tasks[i] <= 109
Note: This question is the same as 2870: Minimum Number of Operations to Make Array Empty.
This problem asks for the minimum number of rounds needed to complete all tasks, given that each round can handle 2 or 3 tasks of the same difficulty level. The solution uses a greedy approach combined with a hash table (or dictionary) for efficient counting.
Approach:
Counting Task Difficulties: First, we count the occurrences of each task difficulty level using a hash table (e.g., Counter
in Python, HashMap
in Java/C++/Rust, Map
in TypeScript). This allows us to process each difficulty level independently.
Checking Feasibility: For each difficulty level, if the count is 1, it's impossible to complete the tasks for that level since we can only do 2 or 3 at a time. In this case, we immediately return -1, indicating that it's not possible to complete all tasks.
Greedy Round Calculation: If the count is greater than 1, we greedily minimize the number of rounds. The most efficient way is to use as many groups of 3 as possible, and then use groups of 2 for any remaining tasks. Mathematically:
rounds = count // 3 + (count % 3 != 0)
This formula does integer division (//
or /
in most languages) to find the number of groups of 3. If there's a remainder (meaning tasks left over after forming groups of 3), we need an additional round to handle those using groups of 2.
Accumulating Rounds: We accumulate the rounds needed for each difficulty level to get the total minimum number of rounds required to complete all tasks.
Time and Space Complexity:
Code Examples (Python and Java):
Python:
from collections import Counter
class Solution:
def minimumRounds(self, tasks: List[int]) -> int:
counts = Counter(tasks)
total_rounds = 0
for count in counts.values():
if count == 1:
return -1 # Impossible to complete if only one task of a type
total_rounds += count // 3 + (count % 3 != 0) #Greedy round calculation
return total_rounds
Java:
import java.util.HashMap;
import java.util.Map;
class Solution {
public int minimumRounds(int[] tasks) {
Map<Integer, Integer> counts = new HashMap<>();
for (int task : tasks) {
counts.put(task, counts.getOrDefault(task, 0) + 1);
}
int totalRounds = 0;
for (int count : counts.values()) {
if (count == 1) {
return -1; // Impossible
}
totalRounds += count / 3 + (count % 3 != 0 ? 1 : 0); //Greedy round calculation
}
return totalRounds;
}
}
The other languages (C++, Go, TypeScript, Rust) follow a very similar structure, using their respective hash table implementations and minor syntax variations. The core logic of counting, checking feasibility, and greedy round calculation remains the same across all the languages.