Minimum Rounds to Complete All Tasks solution and explanation
9 more videos on this problem
Minimum Rounds to Complete All Tasks : Explanation β Live Coding π§π»βπ»π©π»βπ»codestorywithMIK Β· 20:12 Β· 7K views
2244. Minimum Rounds to Complete All Tasks || Leetcode Weekly Contest 289 || Leetcode 2244Bro Coders Β· 11:40 Β· 5K views
Minimum Rounds to Complete All Tasks | Leetcode 2244 | Maps Math | Contest 289 π₯π₯Coding Decoded Β· 12:16 Β· 2K views
MINIMUM ROUNDS TO COMPLETE ALL TASKS | LEETCODE 2244 | PYTHON GREEDY SOLUTIONCracking FAANG Β· 7:40 Β· 1K views
Minimum Rounds to Complete All Tasks | LeetCode 2244 | Theory + Python codeSai Anish Malla Β· 11:00 Β· 826 views
Daily Leetcode #1009: Jan 04, 2023 - 2244. Minimum Rounds to Complete All TasksProgramming Live with Larry Β· 5:44 Β· 779 views
2244. Minimum Rounds to Complete All Tasks (Leetcode Medium)Programming Live with Larry Β· 12:58 Β· 611 views
2244. Minimum Rounds to Complete All Tasks | Leetcode 289Mike the Coder Β· 28:59 Β· 457 views
2 Min | 2244. Minimum Rounds to Complete All Tasks | Contest 289ThinkCode Β· 2:42 Β· 378 views
LeetCode 2244 | Minimum Rounds to Complete All Tasks | Streak π₯| JAVACoding Spark Β· 16:06 Β· 194 views
The problem
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 <= 1051 <= tasks[i] <= 109
Note: This question is the same as 2870: Minimum Number of Operations to Make Array Empty.
Approach overview
Problem Overview: You receive an array where each value represents the difficulty of a task. In one round you can complete either 2 or 3 tasks of the same difficulty. The goal is to determine the minimum number of rounds required to complete all tasks. If any task difficulty appears only once, finishing all tasks becomes impossible.
The key observation: tasks are independent across difficulty levels. You never mix different difficulties in the same round, so the problem reduces to computing the minimum number of rounds needed for each frequency count.
Approach 1: Divide and Conquer with Frequency Breakdown (O(n) time, O(n) space)
Start by counting occurrences of each difficulty using a hash map from the hash table toolkit. Each frequency becomes a smaller subproblem: how many rounds are needed to finish f identical tasks when each round can remove either 2 or 3 tasks. You recursively reduce the count by prioritizing groups of 3 because they minimize the total rounds. When a remainder of 1 appears (for example f = 4 or f = 7), convert one group of 3 into two groups of 2. If a frequency equals 1, the recursion fails because neither 2 nor 3 tasks can be formed.
This approach conceptually divides the problem by difficulty value and solves each group independently. The array scan and hash counting cost O(n) time, and the map stores at most n unique difficulties, so space complexity is O(n). It clearly illustrates why grouping by three tasks produces the fewest rounds.
Approach 2: Dynamic Programming on Task Frequency (O(n) time, O(n) space)
Another way to think about the problem is as a small dynamic programming recurrence. For a given frequency f, define dp[i] as the minimum rounds needed to finish i tasks. The recurrence becomes dp[i] = 1 + min(dp[i-2], dp[i-3]) because each round removes either 2 or 3 tasks. Precompute values up to the maximum frequency found in the array. If a state becomes unreachable (like i = 1), the difficulty cannot be completed.
Before applying DP, compute frequencies using an array traversal and counting step. Then evaluate the recurrence for each frequency and accumulate the result. The DP table grows only up to the largest frequency, so the total work remains linear relative to the number of tasks.
Recommended for interviews: Interviewers expect the counting + greedy reasoning approach. After building the frequency map, compute rounds using the formula ceil(freq / 3) while handling the freq == 1 edge case. This runs in O(n) time with O(n) space and demonstrates strong intuition about greedy grouping. Explaining the DP formulation still helps show deeper understanding of the underlying recurrence.
Approach 1: Divide and Conquer Approach
This approach involves breaking down the problem into smaller subproblems, solving each of them independently, and combining their results in an efficient way. It often uses recursion to handle each subproblem.
def solve_problem(parameters):
# Base case solution
if base_condition:
return
# Divide
mid = calculate_middle
# Conquer
solve_problem(left_part)
solve_problem(right_part)
# Combine
# combine left and right results
solve_problem(initial_parameters)public class Solution {
public void solveProblem(/* parameters */) {
// Base case solution
if (/* base condition */) {
return;
}
// Divide
int mid = /* calculate middle */;
// Conquer
solveProblem(/* left part */);
solveProblem(/* right part */);
// Combine
// combine left and right solutions
}
public static void main(String[] args) {
Solution sol = new Solution();
// Call the method with initial parameters
sol.solveProblem(/* initial parameters */);
}
}#include <iostream>
void solveProblem(/* parameters */) {
// Base case solution
if (/* base condition */) {
return;
}
// Divide
int mid = /* calculate middle */;
// Conquer
solveProblem(/* left part */);
solveProblem(/* right part */);
// Combine
// combine left and right solutions
}
int main() {
// Call the function with initial parameters
solveProblem(/* initial parameters */);
return 0;
}function solveProblem(parameters) {
// Base case solution
if (baseCondition) {
return;
}
// Divide
let mid = calculateMiddle;
// Conquer
solveProblem(leftPart);
solveProblem(rightPart);
// Combine
// combine left and right results
}
solveProblem(initialParameters);#include <stdio.h>
void solveProblem(/* parameters */) {
// Base case solution
if (/* base condition */) {
return;
}
// Divide
int mid = /* calculate middle */;
// Conquer
solveProblem(/* left part */);
solveProblem(/* right part */);
// Combine
// combine left and right solutions
}
int main() {
// Call the function with initial parameters
solveProblem(/* initial parameters */);
return 0;
}class Program {
static void SolveProblem(/* parameters */) {
// Base case solution
if (/* base condition */) {
return;
}
// Divide
int mid = /* calculate middle */;
// Conquer
SolveProblem(/* left part */);
SolveProblem(/* right part */);
// Combine
// combine left and right solutions
}
static void Main() {
SolveProblem(/* initial parameters */);
}
}Python's function uses recursion to handle each subproblem after dividing the original problem. It combines results of subproblems to form the solution to the original problem.
Time Complexity: O(n log n)
Space Complexity: O(log n)
Approach 2: Dynamic Programming Approach
This approach involves solving complex problems by breaking them into simpler overlapping subproblems, storing the results of subproblems to avoid redundant calculations, and constructing a solution from these stored results.
dp = [-1] * 100 # Assume maximum 'n' is 100
def solve_problem(n):
if n == 0 or n == 1:
return n
if dp[n] != -1:
return dp[n]
dp[n] = solve_problem(n - 1) + solve_problem(n - 2)
return dp[n]
n = 10 # Example parameter
print(solve_problem(n))import java.util.Arrays;
public class Solution {
static int[] dp = new int[100]; // Initialize with a large enough size
public static int solveProblem(int n) {
if (n == 0 || n == 1) return n;
if (dp[n] != -1) return dp[n];
dp[n] = solveProblem(n - 1) + solveProblem(n - 2);
return dp[n];
}
public static void main(String[] args) {
Arrays.fill(dp, -1); // Fill the dp array with -1
int n = 10;
System.out.println(solveProblem(n));
}
}#include <iostream>
#include <vector>
std::vector<int> dp(100, -1); // Initialize dp array
int solveProblem(int n) {
if (n == 0 || n == 1) return n;
if (dp[n] != -1) return dp[n];
dp[n] = solveProblem(n-1) + solveProblem(n-2);
return dp[n];
}
int main() {
int n = 10;
std::cout << solveProblem(n) << std::endl;
return 0;
}let dp = new Array(100).fill(-1);
function solveProblem(n) {
if (n === 0 || n === 1) return n;
if (dp[n] !== -1) return dp[n];
dp[n] = solveProblem(n - 1) + solveProblem(n - 2);
return dp[n];
}
let n = 10;
console.log(solveProblem(n));#include <stdio.h>
int dp[100]; // Assuming maximum 'n' is 100 for simplicity
int solveProblem(int n) {
if (n == 0 || n == 1) return n; // Base cases
if (dp[n] != -1) return dp[n]; // Check if already computed
dp[n] = solveProblem(n-1) + solveProblem(n-2);
return dp[n];
}
int main() {
int n = 10; // Example parameter
for (int i = 0; i <= n; i++) dp[i] = -1; // Initialize the dp array
printf("%d\n", solveProblem(n));
return 0;
}using System;
class Program {
static int[] dp = new int[100]; // Assume maximum 'n' is 100
static int SolveProblem(int n) {
if (n == 0 || n == 1) return n;
if (dp[n] != -1) return dp[n];
dp[n] = SolveProblem(n - 1) + SolveProblem(n - 2);
return dp[n];
}
static void Main() {
Array.Fill(dp, -1); // Fill the array with -1
int n = 10;
Console.WriteLine(SolveProblem(n));
}
}Python solution using a list to store the values of subproblems. It recursively calculates and stores results for use in overlapping subproblems.
Time Complexity: O(n)
Space Complexity: O(n)
Approach 3: Hash Table
We use a hash table to count the number of tasks for each difficulty level. Then we traverse the hash table. For each difficulty level, if the number of tasks is 1, then it is impossible to complete all tasks, so we return -1. Otherwise, we calculate the number of rounds needed to complete tasks of this difficulty level and add it to the answer.
Finally, we return the answer.
The time complexity is O(n), and the space complexity is O(n), where n is the length of the tasks array.
function minimumRounds(tasks: number[]): number {
const cnt = new Map();
for (const t of tasks) {
cnt.set(t, (cnt.get(t) || 0) + 1);
}
let ans = 0;
for (const v of cnt.values()) {
if (v == 1) {
return -1;
}
ans += Math.floor(v / 3) + (v % 3 === 0 ? 0 : 1);
}
return ans;
}func minimumRounds(tasks []int) int {
cnt := map[int]int{}
for _, t := range tasks {
cnt[t]++
}
ans := 0
for _, v := range cnt {
if v == 1 {
return -1
}
ans += v / 3
if v%3 != 0 {
ans++
}
}
return ans
}use std::collections::HashMap;
impl Solution {
pub fn minimum_rounds(tasks: Vec<i32>) -> i32 {
let mut cnt = HashMap::new();
for &t in tasks.iter() {
let count = cnt.entry(t).or_insert(0);
*count += 1;
}
let mut ans = 0;
for &v in cnt.values() {
if v == 1 {
return -1;
}
ans += v / 3 + (if v % 3 == 0 { 0 } else { 1 });
}
ans
}
}Complexity comparison
| Approach | Complexity |
|---|---|
| Divide and Conquer Approach | Time Complexity: O(n log n) |
| Dynamic Programming Approach | Time Complexity: O(n) |
| Hash Table | β |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Divide and Conquer with Frequency Counting | O(n) | O(n) | General case. Count tasks and greedily split frequencies into groups of 3 and 2. |
| Dynamic Programming on Frequency | O(n) | O(n) | Useful when modeling the problem as a recurrence or demonstrating DP reasoning in interviews. |
Frequently asked questions
Is Minimum Rounds to Complete All Tasks easy or hard?
Minimum Rounds to Complete All Tasks is rated Medium difficulty on LeetCode. The implementation is short, but recognizing the greedy grouping rule and handling the remainder case correctly requires careful reasoning about frequencies.
Minimum Rounds to Complete All Tasks Python/Java solution
Python and Java implementations typically use a dictionary or HashMap to count task frequencies. After counting, iterate through the map values and compute rounds using ceil(freq / 3) while handling the freq == 1 edge case. Both implementations run in O(n) time with O(n) extra space.
How to solve Minimum Rounds to Complete All Tasks in O(n)?
Traverse the array and store frequencies in a hash map. For each difficulty count f, check if f equals 1; if so return -1. Otherwise compute the required rounds using ceil(f / 3) and add it to the total. This works because using as many groups of 3 as possible minimizes the number of rounds.
What is the best approach for Minimum Rounds to Complete All Tasks?
The best approach uses greedy counting with a hash map. First count how many times each difficulty appears. For a frequency f, the minimum rounds equals ceil(f / 3) because groups of 3 minimize the number of rounds. If any difficulty appears exactly once, the task set cannot be completed and the answer is -1.
Is Minimum Rounds to Complete All Tasks asked at Google/Amazon/Meta?
Problems involving frequency counting and greedy grouping appear frequently in interviews at companies like Amazon, Google, and Meta. The exact LeetCode problem may not always appear, but similar questions testing hash maps, greedy reasoning, and counting strategies are common.
What data structure is used in Minimum Rounds to Complete All Tasks?
A hash table (hash map) is the primary data structure. It stores the frequency of each task difficulty so you can process each group independently. This allows constant-time updates while scanning the array and enables the greedy round calculation.
What is the time complexity of Minimum Rounds to Complete All Tasks?
The optimal solution runs in O(n) time where n is the number of tasks. The algorithm scans the array once to build a frequency map and then processes each unique difficulty in constant time. Space complexity is O(n) in the worst case when all tasks have different difficulties.
